Форум программистов, компьютерный форум, киберфорум
OpenGL
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 5.00/2: Рейтинг темы: голосов - 2, средняя оценка - 5.00
9991 / 2963 / 497
Регистрация: 05.10.2013
Сообщений: 8,144
Записей в блоге: 243

Небольшие примеры на WebGL

19.11.2017, 16:43. Показов 55406. Ответов 200

Студворк — интернет-сервис помощи студентам
Примеры на WebGPU, WebGL и OpenGL: https://www.cyberforum.ru/blogs/416874/6407.html

WebGPU:



В 2026 году изучать WebGPU как никогда актуально. В этой теме приведены примеры как на WebGL, так и на WebGPU. Лучше всего учиться через практику, создавая небольшие демо-проекты.

Стоит стремиться к тому, чтобы писать код самостоятельно из головы, а не просто копировать его. Однако на первых порах можно подглядывать в чужие исходники или ответы нейросетей (Gemini, ChatGPT и др.) и перепечатывать их вручную, попутно уточняя у ИИ назначение тех или иных команд. Со временем лучше чаще обращаться к официальной документации, чтобы глубже понимать работу API.

Здесь находится пример инициализации контекста WebGPU, который заливает холст выбранным цветом:

index.html

PHP/HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!doctype html>
 
<html>
 
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Example</title>
</head>
 
<body>
    <canvas id="renderCanvas" width="300" height="300"></canvas>
 
    <script type="module" src="js/index.js"></script>
</body>
 
</html>
js/index.js

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { context, device, initWebGPUContext } from "./webgpu-context.js";
 
async function init() {
    await initWebGPUContext("renderCanvas");
 
    const commandEncoder = device.createCommandEncoder();
    const textureView = context.getCurrentTexture().createView();
 
    const renderPassDescriptor = {
        colorAttachments: [{
            view: textureView,
            clearValue: { r: 0.92, g: 0.92, b: 0.9, a: 1.0 },
            loadOp: "clear",
            storeOp: "store",
        }]
    };
 
    const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
    passEncoder.end();
 
    device.queue.submit([commandEncoder.finish()]);
}
 
init();
js/webgpu-context.js

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
export let device = null;
export let context = null;
 
export async function initWebGPUContext(canvasName) {
    const canvas = document.getElementById(canvasName);
    if (canvas === null) {
        console.log(`Failed to get a canvas element with the name "${canvasName}"`);
        return false;
    }
 
    if (!navigator.gpu) {
        console.log("WebGPU is not supported in this browser");
        return false;
    }
 
    const adapter = await navigator.gpu.requestAdapter();
    device = await adapter.requestDevice();
 
    context = canvas.getContext("webgpu");
    const format = navigator.gpu.getPreferredCanvasFormat();
 
    context.configure({
        device: device,
        format: format,
        // Equivalent to { alpha: false, premultipliedAlpha: false } in WebGL:
        alphaMode: 'opaque'
    });
 
    return true;
}

WebGPU-Native



Технология WebGPU не ограничивается только браузерами - благодаря кроссплатформенным реализациям (таким как wgpu или Dawn) вы можете писать нативный код на C и C++. Настроив сборку через CMake, один и тот же проект можно легко скомпилировать под Windows, Android, WebAssembly и другие платформы.

Следующие примеры как раз демонстрируют этот подход на практике:

Исходники версии C/C++ Compat могут быть скомпилированы с помощью компиляторов gcc (C) и g++ (C++), но проект настроен на C++. На GitHub в README.md есть ссылки на пошаговое руководство по установке библиотек. Пример собирается в статические исполняемые файлы для Windows, Linux, Android и WebAssembly (Emscripten) из одной кодовой базы с помощью CMake. Все сборки запускаются на своих платформах. Сборки можно скачать на вкладке Releases (сборки есть только в версии на C). Сборка для Linux протестирована на Ubuntu 26 и Fedora 44 на WSL. Сборка для Linux настроена для сборки из под Ubuntu. Ссылка на инструкцию по сборке находится в файле README.md Прямая ссылка на инструкцию по сборке.

WebGL:



Простой треугольник без трансформаций. Для трансформаций можно использовать glMatrix, как в примере: https://plnkr.co/edit/qT6ZTwvncLPRamK5?preview

На русском:





На английском:





Исходники примера:
Содержание темы

Запись в блоге

Краткое описание, что такое WebGL, взятое с https://developer.mozilla.org/... /WebGL_API (там же ссылки на документацию и обучающие материалы):
WebGL (Web Graphics Library) - программная библиотека для языка JavaScript предназначенная для визуализации интерактивной трёхмерной графики и двухмерной графики в пределах совместимости веб-браузера без использования плагинов. WebGL приносит в веб трёхмерную графику, вводя API, который построен на основе OpenGL ES 2.0, что позволяет его использовать в элементах canvas HTML5 .
Какими браузерами поддерживается WebGL, можно посмотреть здесь:
Туториалы:
Литература:
Вложения
Тип файла: zip simple-triangle-webgl-js.zip (1.1 Кб, 0 просмотров)
Тип файла: zip rectangle-drawer-2d-webgl-js-plunker.zip (2.8 Кб, 0 просмотров)
5
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
19.11.2017, 16:43
Ответы с готовыми решениями:

Литература WebGL
подкиньте пожалуйста ссылочек на литературу, можно и платную, можно и зарубежную, но желательно...

Не отрисовывается фигура в Webgl
Здравствуйте. Начинаю осваивать webgl. Начал с изучения этих уроков. Прочитал и вроде бы понял все...

Из какого 3d редактора и как можно экспортировать анимацию в WebGL?
С WebGL дело имею первый раз потому заранее извиняюсь за глупый вопрос и неверные формулировки. 3d...

200
1472 / 827 / 140
Регистрация: 12.10.2013
Сообщений: 5,456
18.01.2021, 15:40
Студворк — интернет-сервис помощи студентам
Был бы интересен пример анимации положения рандом окружностей…с эффектом Боке, DOF, виньетированием, картой градиента и обычным суперсэмплингом.
Название: ScreenShot01435.jpg
Просмотров: 426

Размер: 31.2 Кб
https://ru.wikipedia.org/wiki/Боке
https://ru.wikipedia.org/wiki/... остранства
https://en.wikipedia.org/wiki/Gaussian_blur
https://ru.wikipedia.org/wiki/Виньетирование
https://ru.wikipedia.org/wiki/... глаживания
0
9991 / 2963 / 497
Регистрация: 05.10.2013
Сообщений: 8,144
Записей в блоге: 243
18.01.2021, 21:16  [ТС]
Спрайтовая анимация на Canvas API на JavaScript, Python и C++

Запустить демку в браузере в песочнице Plunker: https://plnkr.co/edit/zjYT0KTfj50MejT9?preview



Исходники:
  • JavaScript, Canvas2D: https://plnkr.co/edit/zjYT0KTfj50MejT9?preview
    Исходники

    index.html

    PHP/HTML
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    <!DOCTYPE html>
    <html lang="en">
     
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Running Cat. Canvas API, JavaScript</title>
        <script src="js/main.js"></script>
    </head>
     
    <body>
        <canvas id="renderCanvas" width="512" height="256"></canvas>
    </body>
     
    </html>
    main.js

    JavaScript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    
    window.onload = () =>
    {
        const ctx = document.getElementById("renderCanvas").getContext("2d");
     
        let sx = 0, sy = 0, sWidth = 512, sHeight = 256; // Source image
        let dx = 0, dy = 0, dWidth = 512, dHeight = 256; // Destination canvas
        // ctx.drawImage(spriteSheet, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
     
        const spriteSheet = new Image();
        spriteSheet.onload = () => { mainLoop(); };
        spriteSheet.src = "assets/sprites-cat-running.png";
     
        let currentTime, deltaTime;
        let lastTime = Date.now();
        let animationTime = 0;
        const animationSpeed = 100;
        const frames = [
            { x: 0, y: 0 }, { x: sWidth, y: 0 }, { x: sWidth * 2, y: 0 }, { x: sWidth * 3, y: 0 },
            { x: 0, y: sHeight }, { x: sWidth, y: sHeight }, { x: sWidth * 2, y: sHeight },
            { x: sWidth * 3, y: sHeight }
        ];
     
        let i = 0; // Frame index
     
        function mainLoop()
        {
            currentTime = Date.now();
            deltaTime = currentTime - lastTime;
            lastTime = currentTime;
     
            animationTime += deltaTime;
            if (animationTime >= animationSpeed)
            {
                animationTime = 0;
                ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
                ctx.drawImage(spriteSheet, frames[i].x, frames[i].y, sWidth, sHeight, dx, dy, dWidth, dHeight);
                i++;
                if (i >= frames.length) { i = 0; }
            }
            requestAnimationFrame(mainLoop);
        }
    };
  • Python, PyQt5, QPainter: https://rextester.com/FDPMLU35222
    Исходники

    Python
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    
    import sys
    from PyQt5.QtWidgets import QApplication, QWidget
    from PyQt5.QtGui import QPainter, QImage
    from PyQt5.QtCore import QTimer, QElapsedTimer, QPoint
     
    class Window(QWidget):
     
        def __init__(self):
            super().__init__()
            self.setWindowTitle("PyQt5")
            self.resize(512, 256)
            # Download a sprite sheet here:
            # https://plnkr.co/edit/zjYT0KTfj50MejT9?preview
            self.sprite_sheet = QImage("sprites-cat-running.png")
            self.sw = 512
            self.sh = 256
            self.frame_index = 0
            self.x = 0
            self.y = 0
            self.frames = []
            for i in range(2):
                for j in range(4):
                    self.frames.append(QPoint(j * self.sw, i * self.sh))
            self.delta_time = 0
            self.animation_time = 0
            self.animation_speed = 100
            self.timer = QTimer()
            self.timer.timeout.connect(self.animationLoop)
            self.elapsedTimer = QElapsedTimer()
            self.timer.start(1000/60)
            
        def animationLoop(self):
            self.delta_time = self.elapsedTimer.elapsed()
            self.elapsedTimer.restart()
            self.animation_time += self.delta_time
            if self.animation_time >= self.animation_speed:
                self.animation_time = 0
                self.x = self.frames[self.frame_index].x()
                self.y = self.frames[self.frame_index].y()
                self.frame_index += 1
                if self.frame_index >= len(self.frames):
                    self.frame_index = 0
            self.update()
     
        def paintEvent(self, event):
            qp = QPainter(self)
            qp.drawImage(0, 0, self.sprite_sheet, self.x, self.y, self.sw, self.sh)
     
    def main():
        app = QApplication(sys.argv)
        w = Window()
        w.show()
        sys.exit(app.exec_())
     
    if __name__ == "__main__":
        main()
  • Python, PySide2, QPainter: https://rextester.com/YLSNG7380
    Исходники

    Python
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    
    import sys
    from PySide2.QtWidgets import QApplication, QWidget
    from PySide2.QtGui import QPainter, QImage
    from PySide2.QtCore import QTimer, QElapsedTimer, QPoint
     
    class Window(QWidget):
     
        def __init__(self):
            super().__init__()
            self.setWindowTitle("PySide2")
            self.resize(512, 256)
            # Download a sprite sheet here:
            # https://plnkr.co/edit/zjYT0KTfj50MejT9?preview
            self.sprite_sheet = QImage("sprites-cat-running.png")
            self.sw = 512
            self.sh = 256
            self.frame_index = 0
            self.x = 0
            self.y = 0
            self.frames = []
            for i in range(2):
                for j in range(4):
                    self.frames.append(QPoint(j * self.sw, i * self.sh))
            self.delta_time = 0
            self.animation_time = 0
            self.animation_speed = 100
            self.timer = QTimer()
            self.timer.timeout.connect(self.animationLoop)
            self.elapsedTimer = QElapsedTimer()
            self.timer.start(1000/60)
            
        def animationLoop(self):
            self.delta_time = self.elapsedTimer.elapsed()
            self.elapsedTimer.restart()
            self.animation_time += self.delta_time
            if self.animation_time >= self.animation_speed:
                self.animation_time = 0
                self.x = self.frames[self.frame_index].x()
                self.y = self.frames[self.frame_index].y()
                self.frame_index += 1
                if self.frame_index >= len(self.frames):
                    self.frame_index = 0
            self.update()
     
        def paintEvent(self, event):
            qp = QPainter(self)
            qp.drawImage(0, 0, self.sprite_sheet, self.x, self.y, self.sw, self.sh)
     
    def main():
        app = QApplication(sys.argv)
        w = Window()
        w.show()
        sys.exit(app.exec_())
     
    if __name__ == "__main__":
        main()
  • C++, Qt5, QPainter: https://rextester.com/XEUPHQ83360
    Исходники

    C++ (Qt)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    
    #include <QtWidgets/QApplication>
    #include <QtWidgets/QWidget>
    #include <QtGui/QPainter>
    #include <QtGui/QImage>
    #include <QtCore/QTimer>
    #include <QtCore/QElapsedTimer>
    #include <QtCore/QDebug>
     
    #define N_FRAMES 8
     
    class Window : public QWidget
    {
        Q_OBJECT
    public:
        Window()
        {
            setWindowTitle("Qt C++");
            resize(512, 256);
            m_spriteSheet.load(":/Sprites/sprites-cat-running.png");
            int index = 0;
            for (int i = 0; i < 2; i++ )
            {
                for (int j = 0; j < 4; j++)
                {
                    m_frames[index] = QPoint(j * m_sw, i * m_sh);
                    qDebug() << m_frames[index];
                    index++;
                }
            }
            connect(&m_timer, &QTimer::timeout, this, &Window::animationLoop);
            m_timer.start(1000.f/60.f);
            m_elapsedTimer.start();
        }
    private:
        QTimer m_timer;
        QElapsedTimer m_elapsedTimer;
        float m_deltaTime;
        float m_animationTime = 0.f;
        const float m_animationSpeed = 100.f;
        QImage m_spriteSheet;
        QPoint m_frames[N_FRAMES];
        int m_frameIndex = 0;
        int m_x, m_y;
        const int m_sw = 512, m_sh = 256; // Source image width and height
    private slots:
        void animationLoop()
        {
            m_deltaTime = m_elapsedTimer.elapsed();
            m_elapsedTimer.restart();
     
            m_animationTime += m_deltaTime;
     
            if (m_animationTime > m_animationSpeed)
            {
                m_animationTime = 0;
                m_x = m_frames[m_frameIndex].x();
                m_y = m_frames[m_frameIndex].y();
                m_frameIndex++;
                if (m_frameIndex >= N_FRAMES)
                {
                    m_frameIndex = 0;
                }
            }
     
            update();
        }
    private:
        void paintEvent(QPaintEvent *event)
        {
            Q_UNUSED(event);
            QPainter qp(this);
            qp.drawImage(0, 0, m_spriteSheet, m_x, m_y, m_sw, m_sh);
        }
    };
     
    #include "main.moc"
     
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        Window w;
        w.show();
        return a.exec();
    }

Данный пример не использует WebGL, но он очень кратно демонстрирует принцип спрайтовой анимации. Попробуйте реализовать этот принцип самостоятельно на WebGL и OpenGL. Лучший способ изучения - это написание кода самостоятельно с нуля до перехода знаний в навыки через многократное повторение изученного на практике. У меня есть короткий пример спрайтовой анимации на WebGL и OpenGL, но я его пока выкладывать не буду, чтобы у вас было время попробовать самостоятельно решить эту задачу.
1
1472 / 827 / 140
Регистрация: 12.10.2013
Сообщений: 5,456
18.01.2021, 23:28
Цитата Сообщение от 8Observer8 Посмотреть сообщение
У меня есть короткий пример спрайтовой анимации на WebGL и OpenGL, но я его пока выкладывать не буду, чтобы у вас было время попробовать самостоятельно решить эту задачу.
Не я спрайты не осилю, давно искал но никак =(.

Интересен был бы пример салюта.
Название: Video_2021-01-18_221736_New.gif
Просмотров: 384

Размер: 270.6 Кб
Система частиц. Процедурная генерация текстуры из N фреймов где точка размыта и плавно меняет цвет и размер. Затем эта текстура используется для спрайтов. Получаем гибкость процедурной генерации и скорость работы т.к. спрайт текстура. Каждый спрайт это материальная точка в поле гравитации. Полет от импульса силы…вроде так делают.Еще там нужно след от частицы оставить…хз как.
0
9991 / 2963 / 497
Регистрация: 05.10.2013
Сообщений: 8,144
Записей в блоге: 243
23.01.2021, 00:06  [ТС]
Excalibur921, чтобы вы больше не флудили в мой адрес после каждого моего сообщения здесь, я вам сообщаю, что я вас добавил в список игнорирования, а ещё я добавил фильтры в AdblockPlus, которые удаляю целиком ваши сообщения из моего браузера, цитаты, и ваш никнейм (отовсюду), то есть для моего браузера вы вообще не существуете на форуме. Вы не один такой - я так сделал с десятком людей, сообщения которых и упоминания о которых меня раздражали. Больше в мою сторону не пишите, я вас вообще не вижу.

Например, между двумя моими сообщениями теперь нет вашего сообщения, а так же нет цитаты с вашим текстом в моём сообщении:



Фильтр даже в реальном времени удалил ваш ник из текущего сообщения:

Название: 0525936e-ca58-4bd6-a9a2-ad265b547dee.png
Просмотров: 409

Размер: 1.6 Кб
0
1472 / 827 / 140
Регистрация: 12.10.2013
Сообщений: 5,456
23.01.2021, 11:13
Цитата Сообщение от 8Observer8 Посмотреть сообщение
я так сделал с десятком людей
Омг…подлечите голову.
0
9991 / 2963 / 497
Регистрация: 05.10.2013
Сообщений: 8,144
Записей в блоге: 243
24.02.2021, 23:55  [ТС]
Использование физического движка Planck.js вместе с TypeScript (Planck.js - это порт физического 2D-движка Box2D)

Скачать исходники: hello-planckjs-webgl10-ts.zip (4.8 Кб)

Исходники на GitHub: hello-planckjs-webgl10-ts

Установите глобально следующие пакеты:
  • npm i typescript -g
  • npm i browserify -g
  • npm i uglify-js -g

Установите пакеты из `package.json` командой: npm install

Раскомментируйте/Закомментируйте Debug/Release в файлах `index.html` и `main.ts` (см. комментарии в этих файлах).

Используйте следующие комманды для сборки:

- `npm run debug` - для отладки в редакторах кода и для публикации в песочницах, например, в Plunker: Hello Planck.js. WebGL 1.0, TypeScript
- `npm run release` - для сборки в `bundle.min.js` для production

package.json
JSON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
  "name": "hello-planckjs-webgl10-ts",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "debug": "tsc -p tsconfigs/tsconfig.debug.json",
    "compile": "tsc -p tsconfigs/tsconfig.release.json",
    "bundle": "browserify public/js/main.js -o public/js/bundle.js",
    "minify": "uglifyjs public/js/bundle.js -o public/js/bundle.min.js",
    "release": "npm run compile && npm run bundle && npm run minify"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "gl-matrix": "^3.3.0",
    "planck-js": "^0.3.23",
    "requirejs": "^2.3.6"
  },
  "devDependencies": {
    "@types/requirejs": "^2.1.32"
  }
}


public/index.html
PHP/HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    
    <title>Hello Planck. WebGL 1.0, TypeScript</title>
 
    <!-- Debug -->
    <script data-main="js/RequireConfig"
        src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js"></script>
    <!-- Release -->
    <!-- <script src="js/bundle.min.js"></script> -->
</head>
 
<body>
    <canvas id="renderCanvas" width="300" height="150"></canvas>
 
    <div id="output"></div>
 
    <a href="https://github.com/8Observer8/hello-planckjs-webgl10-ts">Source Code on GitHub</a>
    <br>
    <a href="https://plnkr.co/edit/MyJOyvRtIDAhpKA5?preview">Playground</a>
</body>
 
</html>


src/client/main.ts
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import { mat4 } from "gl-matrix";
import { Vec2 } from "planck-js";
 
let gl: WebGLRenderingContext;
let output: HTMLDivElement;
 
function init()
{
    const canvas = document.getElementById("renderCanvas") as HTMLCanvasElement;
    gl = canvas.getContext("webgl");
    gl.clearColor(0.2, 0.2, 0.2, 1);
    gl.clear(gl.COLOR_BUFFER_BIT);
 
    output = document.getElementById("output") as HTMLDivElement;
 
    const vec = Vec2(1, 2);
    output.innerHTML = `vec = (${vec.x}, ${vec.y})<br>`;
 
    const matrix = mat4.create();
    output.innerHTML += `matrix = [${matrix}]`;
}
 
function main()
{
    init();
}
 
// Debug
main();
 
// Release
// window.onload = () => main();


src/client/RequireConfig.ts
JavaScript
1
2
3
4
5
6
7
8
9
requirejs.config({
    baseUrl: "js",
    paths: {
        "gl-matrix": "https://cdn.jsdelivr.net/npm/gl-matrix@3.3.0/gl-matrix-min",
        "planck-js": "https://cdn.jsdelivr.net/npm/planck-js@0.3.23/dist/planck.min"
    }
});
 
requirejs(["main"], () => { });


tsconfigs/tsconfig.json
JSON
1
2
3
4
5
6
7
8
9
{
    "compilerOptions": {
        "target": "ES5",
        "outDir": "../public/js"
    },
    "include": [
        "../src/client/**/*.ts"
    ]
}


tsconfigs/tsconfig.debug.json
JSON
1
2
3
4
5
6
7
8
9
10
11
12
13
{
    "extends": "./tsconfig.json",
    "compilerOptions": {
        "module": "AMD",
        "sourceMap": true,
        "types": [
            "requirejs",
            "gl-matrix",
            "planck-js"
        ],
        "moduleResolution": "node"
    }
}


tsconfigs/tsconfig.release.json
JSON
1
2
3
4
5
6
7
8
9
10
11
12
13
{
    "extends": "./tsconfig.json",
    "compilerOptions": {
        "module": "CommonJS",
        "sourceMap": false,
        "types": [
            "node"
        ]
    },
    "exclude": [
        "../src/client/RequireConfig.ts"
    ]
}
Вложения
Тип файла: zip hello-planckjs-webgl10-ts.zip (4.8 Кб, 0 просмотров)
1
9991 / 2963 / 497
Регистрация: 05.10.2013
Сообщений: 8,144
Записей в блоге: 243
25.02.2021, 00:05  [ТС]
Использование физического движка Ammo.js вместе с TypeScript (Ammo.js - это порт физического 3D-движка Bullet)

Скачать исходники: hello-ammojs-webgl10-ts.zip (46.0 Кб)

Исходники на GitHub: hello-ammojs-webgl10-ts

Установите глобально следующие пакеты:
  • npm i typescript -g
  • npm i browserify -g
  • npm i uglify-js -g

Установите пакеты из `package.json` командой: npm install

Раскомментируйте/Закомментируйте Debug/Release в файлах `index.html` и `main.ts` (см. комментарии в этих файлах).

Используйте следующие комманды для сборки:

- `npm run debug` - для отладки в редакторах кода и для публикации в песочницах, например, в Plunker: Hello Ammo.js. WebGL 1.0, TypeScript
- `npm run release` - для сборки в `bundle.min.js` для production

package.json
JSON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
  "name": "hello-ammojs-webgl10-ts",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "debug": "tsc -p tsconfigs/tsconfig.debug.json",
    "compile": "tsc -p tsconfigs/tsconfig.release.json",
    "bundle": "browserify public/js/main.js -o public/js/bundle.js",
    "minify": "uglifyjs public/js/bundle.js -o public/js/bundle.min.js",
    "release": "npm run compile && npm run bundle && npm run minify"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "ammo.js": "github:kripken/ammo.js",
    "requirejs": "^2.3.6"
  },
  "devDependencies": {
    "@types/requirejs": "^2.1.32",
    "ammojs-typed": "^1.0.6"
  }
}


public/index.html
PHP/HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Hello Ammo. WebGL 1.0, TypeScript</title>
 
    <!-- Debug -->
    <script data-main="js/RequireConfig"
        src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js"></script>
    <!-- Release -->
    <!-- <script src="js/bundle.min.js"></script> -->
</head>
 
<body>
    <canvas id="renderCanvas" width="300" height="150"></canvas>
 
    <div id="output"></div>
 
    <a href="https://github.com/8Observer8/hello-ammojs-webgl10-ts">Source Code on GitHub</a>
    <br>
    <a href="https://plnkr.co/edit/6KQT9VQHWvswY3cc?preview">Playground</a>
</body>
 
</html>


src/client/main.ts
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import { mat4 } from "gl-matrix";
import AmmoModule from "ammojs-typed";
 
let Ammo: typeof AmmoModule;
let gl: WebGLRenderingContext;
let output: HTMLDivElement;
 
function init()
{
    const canvas = document.getElementById("renderCanvas") as HTMLCanvasElement;
    gl = canvas.getContext("webgl");
    gl.clearColor(0.2, 0.2, 0.2, 1);
    gl.clear(gl.COLOR_BUFFER_BIT);
 
    output = document.getElementById("output") as HTMLDivElement;
 
    const vec = new Ammo.btVector3(1, 2, 3);
    output.innerHTML = `vec = (${vec.x()}, ${vec.y()}, ${vec.z()})<br>`;
 
    const matrix = mat4.create();
    output.innerHTML += `matrix = [${matrix}]`;
}
 
function main()
{
    AmmoModule().then((api) =>
    {
        Ammo = api;
        init();
    });
}
 
// Debug
main();
 
// Release
// window.onload = () => main();


src/client/RequireConfig.ts
JavaScript
1
2
3
4
5
6
7
8
9
requirejs.config({
    baseUrl: "js",
    paths: {
        "gl-matrix": "https://cdn.jsdelivr.net/npm/gl-matrix@3.3.0/gl-matrix-min",
        "ammojs-typed": "https://dl.dropboxusercontent.com/s/e5iytx67noqoew7/ammo"
    }
});
 
requirejs(["main"], () => { });


tsconfigs/tsconfig.json
JSON
1
2
3
4
5
6
7
8
9
10
11
{
    "compilerOptions": {
        "target": "ES5",
        "outDir": "../public/js",
        "allowSyntheticDefaultImports": true,
        "esModuleInterop": true
    },
    "include": [
        "../src/client/**/*.ts"
    ]
}


tsconfigs/tsconfig.debug.json
JSON
1
2
3
4
5
6
7
8
9
10
11
12
13
{
    "extends": "./tsconfig.json",
    "compilerOptions": {
        "module": "AMD",
        "sourceMap": true,
        "types": [
            "requirejs",
            "gl-matrix",
            "ammojs-typed"
        ],
        "moduleResolution": "node"
    }
}


tsconfigs/tsconfig.release.json
JSON
1
2
3
4
5
6
7
8
9
10
11
12
13
{
    "extends": "./tsconfig.json",
    "compilerOptions": {
        "module": "CommonJS",
        "sourceMap": false,
        "types": [
            "node"
        ]
    },
    "exclude": [
        "../src/client/RequireConfig.ts"
    ]
}
Вложения
Тип файла: zip hello-ammojs-webgl10-ts.zip (46.0 Кб, 0 просмотров)
0
9991 / 2963 / 497
Регистрация: 05.10.2013
Сообщений: 8,144
Записей в блоге: 243
25.02.2021, 00:39  [ТС]
Пример падения кругов с буквами с использованием физического 2D-движка Matter.js, WebGL 1.0 и TypeScript

Круги создал в Blender, текстуры букв наложил в GIMP (GIMP - это бесплатный аналог Photoshop'а). Цвета взял из логотипа форума в левом верхнем углу пипеткой в GIMP. Шрифт созданный - Sans-serif - вроде совпадает с тем, что на логотипе. Экспортировал круги в формат .dae (COLLADA). Импортировал с помощью встроенного в TypeScript XML-парсера.

Запустить в браузере (падение запускается кликом левой кнопки мыши в любом месте экрана)



Скачать исходники: falling-cyberforum-matterjs-ts.zip (70.8 Кб)

Исходники на GitHub: falling-cyberforum-matterjs-ts

public/assets/shaders/texturedShader.vert

glSlang
1
2
3
4
5
6
7
8
9
10
attribute vec4 aPosition;
attribute vec2 aTexCoord;
uniform mat4 uMvpMatrix;
varying vec2 vTexCoord;
 
void main()
{
    gl_Position = uMvpMatrix * aPosition;
    vTexCoord = aTexCoord;
}
public/assets/shaders/texturedShader.frag

glSlang
1
2
3
4
5
6
7
8
9
precision mediump float;
 
uniform sampler2D uSampler;
varying vec2 vTexCoord;
 
void main()
{
    gl_FragColor = texture2D(uSampler, vTexCoord);
}
public/index.html

PHP/HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 
    <title>Falling CyberForum. Matter.js, WebGL 1.0, TypeScript</title>
 
    <link rel="stylesheet" href="css/style.css">
</head>
 
<body>
    <canvas id="renderCanvas"></canvas>
 
    <!-- Debug -->
    <script data-main="js/requireConfig"
        src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js"></script>
    <!-- Release -->
    <!-- <script src="js/bundle.min.js"></script> -->
</body>
 
</html>
public/style.css

CSS
1
2
3
4
5
6
7
8
9
10
11
12
13
html, body {
    overflow: hidden;
    width: 100%;
    height: 100%;
    margin: 0px;
    padding: 0px;
}
 
#renderCanvas {
    touch-action: none;
    width: 100%;
    height: 100%;
}
src/client/main.ts

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
import { mat4, vec3 } from "gl-matrix";
import * as Matter from "matter-js";
import { loadAssets } from "./loaders";
import Locations from "./Locations";
import ObjectForGraphics from "./ObjectForGraphics";
import { createShaderProgram } from "./shaderProgram";
import { initVertexBuffers } from "./vertexBuffers";
import { createTexture } from "./textures";
import ObjectForPhysics from "./ObjectForPhysics";
 
let gl: WebGLRenderingContext;
let program: WebGLProgram;
const viewMatrix = mat4.create();
const projectionMatrix = mat4.create();
const viewProjMatrix = mat4.create();
let currentTime: number, lastTime: number, deltaTime: number;
let letter_c: ObjectForGraphics;
let letter_y: ObjectForGraphics;
let letter_b: ObjectForGraphics;
let letter_e: ObjectForGraphics;
let letter_r1: ObjectForGraphics;
let letter_f: ObjectForGraphics;
let letter_o: ObjectForGraphics;
let letter_r2: ObjectForGraphics;
let letter_u: ObjectForGraphics;
let letter_m: ObjectForGraphics;
let ground1: ObjectForGraphics;
let ground2: ObjectForGraphics;
let ground3: ObjectForGraphics;
let ground4: ObjectForGraphics;
const worldHeight = 50;
 
const textFiles: { name: string, path: string, content: string }[] = [];
const models: { name: string, path: string, content: Document }[] = [];
const images: { name: string, path: string, content: HTMLImageElement }[] = [];
 
function init(): void
{
    const canvas = document.getElementById("renderCanvas") as HTMLCanvasElement;
    gl = canvas.getContext("webgl");
 
    gl.clearColor(0.15, 0.15, 0.15, 1.0);
    gl.enable(gl.DEPTH_TEST);
 
    const vertShaderSrc = textFiles.filter(asset => { return asset.name === "vertShaderSrc" })[0].content;
    const fragShaderSrc = textFiles.filter(asset => { return asset.name === "fragShaderSrc" })[0].content;
    program = createShaderProgram(gl, vertShaderSrc, fragShaderSrc);
 
    const locations = new Locations();
    locations.aPositionLocation = gl.getAttribLocation(program, "aPosition");
    locations.aTextureCoordLocation = gl.getAttribLocation(program, "aTexCoord");
    locations.uMvpMatrixLocation = gl.getUniformLocation(program, "uMvpMatrix");
 
    const letterImage = images.filter(asset => { return asset.name == "lettersTexture" })[0].content;
    const letterTexture = createTexture(gl, letterImage);
 
    const size = 2;
    const y1 = 10;
    const y2 = 5;
 
    const engine = Matter.Engine.create();
 
    const groundFriction = 0.5;
    const groundRestitution = 0.8;
 
    const ground1Body = Matter.Bodies.rectangle(-14, 0, 20, 2,
        { isStatic: true, angle: -20 * Math.PI / 180 });
    ground1Body.friction = groundFriction;
    ground1Body.restitution = groundRestitution;
 
    const ground2Body = Matter.Bodies.rectangle(14, 0, 20, 2,
        { isStatic: true, angle: 20 * Math.PI / 180 });
    ground2Body.friction = groundFriction;
    ground2Body.restitution = groundRestitution;
 
    const ground3Body = Matter.Bodies.rectangle(-8, -10, 20, 2,
        { isStatic: true, angle: -20 * Math.PI / 180 });
    ground3Body.friction = groundFriction;
    ground3Body.restitution = groundRestitution;
 
    const ground4Body = Matter.Bodies.rectangle(8, -10, 20, 2,
        { isStatic: true, angle: 20 * Math.PI / 180 });
    ground4Body.friction = groundFriction;
    ground4Body.restitution = groundRestitution;
 
    const letterFriction = 0.5;
    const letterRestitution = 0.8;
 
    engine.world.gravity.y = -0.2;
 
    const cBody = Matter.Bodies.circle(-10, y1, size);
    cBody.friction = letterFriction;
    cBody.restitution = letterRestitution;
 
    const yBody = Matter.Bodies.circle(-5, y1, size);
    yBody.friction = letterFriction;
    yBody.restitution = letterRestitution;
 
    const bBody = Matter.Bodies.circle(0, y1, size);
    yBody.friction = letterFriction;
    yBody.restitution = letterRestitution;
 
    const eBody = Matter.Bodies.circle(5, y1, size);
    eBody.friction = letterFriction;
    eBody.restitution = letterRestitution;
 
    const r1Body = Matter.Bodies.circle(10, y1, size);
    r1Body.friction = letterFriction;
    r1Body.restitution = letterRestitution;
 
    const fBody = Matter.Bodies.circle(-10, y2, size);
    fBody.friction = letterFriction;
    fBody.restitution = letterRestitution;
 
    const oBody = Matter.Bodies.circle(-5, y2, size);
    oBody.friction = letterFriction;
    oBody.restitution = letterRestitution;
 
    const r2Body = Matter.Bodies.circle(0, y2, size);
    r2Body.friction = letterFriction;
    r2Body.restitution = letterRestitution;
 
    const uBody = Matter.Bodies.circle(5, y2, size);
    uBody.friction = letterFriction;
    uBody.restitution = letterRestitution;
 
    const mBody = Matter.Bodies.circle(10, y2, size);
    mBody.friction = letterFriction;
    mBody.restitution = letterRestitution;
 
    Matter.World.add(engine.world, [ground1Body, ground2Body, ground3Body, ground4Body,
        cBody, yBody, bBody, eBody, r1Body, fBody, oBody, r2Body, uBody, mBody]);
 
    let letterXML = models.filter(asset => { return asset.name === "letter_c" })[0].content;
    let letterVertexBuffers = initVertexBuffers(gl, letterXML);
    letter_c = new ObjectForPhysics(cBody, letterVertexBuffers, locations, letterTexture);
 
    letterXML = models.filter(asset => { return asset.name === "letter_y" })[0].content;
    letterVertexBuffers = initVertexBuffers(gl, letterXML);
    letter_y = new ObjectForPhysics(yBody, letterVertexBuffers, locations, letterTexture);
 
    letterXML = models.filter(asset => { return asset.name === "letter_b" })[0].content;
    letterVertexBuffers = initVertexBuffers(gl, letterXML);
    letter_b = new ObjectForPhysics(bBody, letterVertexBuffers, locations, letterTexture);
 
    letterXML = models.filter(asset => { return asset.name === "letter_e" })[0].content;
    letterVertexBuffers = initVertexBuffers(gl, letterXML);
    letter_e = new ObjectForPhysics(eBody, letterVertexBuffers, locations, letterTexture);
 
    letterXML = models.filter(asset => { return asset.name === "letter_r1" })[0].content;
    letterVertexBuffers = initVertexBuffers(gl, letterXML);
    letter_r1 = new ObjectForPhysics(r1Body, letterVertexBuffers, locations, letterTexture);
 
    letterXML = models.filter(asset => { return asset.name === "letter_f" })[0].content;
    letterVertexBuffers = initVertexBuffers(gl, letterXML);
    letter_f = new ObjectForPhysics(fBody, letterVertexBuffers, locations, letterTexture);
 
    letterXML = models.filter(asset => { return asset.name === "letter_o" })[0].content;
    letterVertexBuffers = initVertexBuffers(gl, letterXML);
    letter_o = new ObjectForPhysics(oBody, letterVertexBuffers, locations, letterTexture);
 
    letterXML = models.filter(asset => { return asset.name === "letter_r2" })[0].content;
    letterVertexBuffers = initVertexBuffers(gl, letterXML);
    letter_r2 = new ObjectForPhysics(r2Body, letterVertexBuffers, locations, letterTexture);
 
    letterXML = models.filter(asset => { return asset.name === "letter_u" })[0].content;
    letterVertexBuffers = initVertexBuffers(gl, letterXML);
    letter_u = new ObjectForPhysics(uBody, letterVertexBuffers, locations, letterTexture);
 
    letterXML = models.filter(asset => { return asset.name === "letter_m" })[0].content;
    letterVertexBuffers = initVertexBuffers(gl, letterXML);
    letter_m = new ObjectForPhysics(mBody, letterVertexBuffers, locations, letterTexture);
 
    // letter_c.position = [-10, y1, 0];
    letter_c.scale = [size, size, 1];
    // letter_y.position = [-5, y1, 0];
    letter_y.scale = [size, size, 1];
    // letter_b.position = [0, y1, 0];
    letter_b.scale = [size, size, 1];
    // letter_e.position = [5, y1, 0];
    letter_e.scale = [size, size, 1];
    // letter_r1.position = [10, y1, 0];
    letter_r1.scale = [size, size, 1];
    // letter_f.position = [-10, y2, 0];
    letter_f.scale = [size, size, 1];
    // letter_o.position = [-5, y2, 0];
    letter_o.scale = [size, size, 1];
    // letter_r2.position = [0, y2, 0];
    letter_r2.scale = [size, size, 1];
    // letter_u.position = [5, y2, 0];
    letter_u.scale = [size, size, 1];
    // letter_m.position = [10, y2, 0];
    letter_m.scale = [size, size, 1];
 
    const groundXML = models.filter(asset => { return asset.name === "ground" })[0].content;
    const groundVertexBuffers = initVertexBuffers(gl, groundXML);
 
    ground1 = new ObjectForPhysics(ground1Body, groundVertexBuffers, locations, letterTexture);
    // ground1.position = [-12, 0, 0];
    ground1.scale = [10, 2, 1];
    // ground1.angle = -20;
 
    ground2 = new ObjectForPhysics(ground2Body, groundVertexBuffers, locations, letterTexture);
    // ground2.position = [12, 0, 0];
    ground2.scale = [10, 2, 1];
    // ground2.angle = 20 * Math.PI / 180;
 
    ground3 = new ObjectForPhysics(ground3Body, groundVertexBuffers, locations, letterTexture);
    // ground3.position = [-8, -10, 0];
    ground3.scale = [10, 2, 1];
    // ground3.angle = -20 * Math.PI / 180;
 
    ground4 = new ObjectForPhysics(ground4Body, groundVertexBuffers, locations, letterTexture);
    // ground4.position = [8, -10, 0];
    ground4.scale = [10, 2, 1];
    // ground4.angle = 20 * Math.PI / 180;
 
    mat4.lookAt(
        viewProjMatrix,
        vec3.fromValues(0, 0, 100),
        vec3.fromValues(0, 0, 0),
        vec3.fromValues(0, 1, 0));
 
    let firstClick = true;
 
    canvas.onclick = (event) =>
    {
        if (firstClick && event.button == 0)
        {
            Matter.Engine.run(engine);
            firstClick = false;
        }
    };
 
    window.onresize = () =>
    {
        const w = (gl.canvas as HTMLCanvasElement).clientWidth;
        const h = (gl.canvas as HTMLCanvasElement).clientHeight;
        gl.canvas.width = w;
        gl.canvas.height = h;
        gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
        const aspect = w / h;
        const worldWidth = aspect * worldHeight;
        mat4.ortho(projectionMatrix,
            -worldWidth / 2, worldWidth / 2,
            -worldHeight / 2, worldHeight / 2, 50, -50);
        lastTime = Date.now();
        draw();
    };
    window.onresize(null);
}
 
function draw(): void
{
    gl.clear(gl.COLOR_BUFFER_BIT);
    mat4.mul(viewProjMatrix, projectionMatrix, viewMatrix);
 
    currentTime = Date.now();
    deltaTime = (currentTime - lastTime) / 1000;
    lastTime = currentTime;
 
    letter_c.draw(gl, program, viewProjMatrix);
    letter_y.draw(gl, program, viewProjMatrix);
    letter_b.draw(gl, program, viewProjMatrix);
    letter_e.draw(gl, program, viewProjMatrix);
    letter_r1.draw(gl, program, viewProjMatrix);
    letter_f.draw(gl, program, viewProjMatrix);
    letter_o.draw(gl, program, viewProjMatrix);
    letter_r2.draw(gl, program, viewProjMatrix);
    letter_u.draw(gl, program, viewProjMatrix);
    letter_m.draw(gl, program, viewProjMatrix);
 
    ground1.draw(gl, program, viewProjMatrix);
    ground2.draw(gl, program, viewProjMatrix);
    ground3.draw(gl, program, viewProjMatrix);
    ground4.draw(gl, program, viewProjMatrix);
 
    requestAnimationFrame(() => draw());
}
 
function main(): void
{
    textFiles.push({ name: "vertShaderSrc", path: "assets/shaders/texturedShader.vert", content: "" });
    textFiles.push({ name: "fragShaderSrc", path: "assets/shaders/texturedShader.frag", content: "" });
    images.push({ name: "lettersTexture", path: "assets/models/letters.png", content: null });
    models.push({ name: "letter_c", path: "assets/models/letter_c.dae", content: null });
    models.push({ name: "letter_y", path: "assets/models/letter_y.dae", content: null });
    models.push({ name: "letter_b", path: "assets/models/letter_b.dae", content: null });
    models.push({ name: "letter_e", path: "assets/models/letter_e.dae", content: null });
    models.push({ name: "letter_r1", path: "assets/models/letter_r1.dae", content: null });
    models.push({ name: "letter_f", path: "assets/models/letter_f.dae", content: null });
    models.push({ name: "letter_o", path: "assets/models/letter_o.dae", content: null });
    models.push({ name: "letter_r2", path: "assets/models/letter_r2.dae", content: null });
    models.push({ name: "letter_u", path: "assets/models/letter_u.dae", content: null });
    models.push({ name: "letter_m", path: "assets/models/letter_m.dae", content: null });
    models.push({ name: "ground", path: "assets/models/ground.dae", content: null });
 
    loadAssets(textFiles, models, images, () =>
    {
        init();
    });
}
 
// Debug
main();
 
// Release
// window.onload = () => main();
src/client/loaders.ts

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
export function loadAssets(
    textFiles: { name: string, path: string, content: string }[],
    models: { name: string, path: string, content: Document }[],
    images: { name: string, path: string, content: HTMLImageElement }[],
    finishedCallback: () => void)
{
    let amountToLoad = textFiles.length + models.length + images.length;
 
    for (let i = 0; i < textFiles.length; i++)
    {
        loadFile(textFiles[i].path, true,
            (src) => { textFiles[i].content = src as string; areLoaded(); });
    }
 
    for (let i = 0; i < models.length; i++)
    {
        loadFile(models[i].path, false,
            (src) => { models[i].content = src as Document; areLoaded(); });
    }
 
    for (let i = 0; i < images.length; i++)
    {
        loadImage(images[i].path,
            (image) => { images[i].content = image; areLoaded(); });
    }
 
    function areLoaded()
    {
        amountToLoad--;
        if (amountToLoad === 0)
        {
            finishedCallback();
        }
    }
}
 
export function loadImage(path, callback: (img: HTMLImageElement) => void)
{
    const image = new Image();
    image.onload = () => { callback(image) };
    image.src = path;
}
 
export function loadFile(path: string, isTextFile: boolean, callback: (content: string | Document) => void)
{
    const xhr = new XMLHttpRequest();
 
    xhr.onreadystatechange = () =>
    {
        if (xhr.readyState === 4 && xhr.status !== 404)
        {
            if (isTextFile)
            {
                callback(xhr.responseText);
            }
            else
            {
                callback(xhr.responseXML);
            }
        }
    };
 
    xhr.open("GET", path, true);
    xhr.send();
}
продолжение в слевующем сообщении
Вложения
Тип файла: zip falling-cyberforum-matterjs-ts.zip (70.8 Кб, 0 просмотров)
0
9991 / 2963 / 497
Регистрация: 05.10.2013
Сообщений: 8,144
Записей в блоге: 243
25.02.2021, 00:40  [ТС]
продолжение предыдущего сообщения

src/client/Locations.ts

JavaScript
1
2
3
4
5
6
export default class Locations
{
    public aPositionLocation: number;
    public aTextureCoordLocation: number;
    public uMvpMatrixLocation: WebGLUniformLocation;
}
src/client/ObjectForGraphics.ts

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import { mat4, vec3 } from "gl-matrix";
import Locations from "./Locations";
import VertexBuffersCollection from "./VertexBuffersCollection";
 
export default class ObjectForGraphics
{
    public position = [0, 0, 0];
    public angle = 0;
    public scale = [1, 1, 1];
 
    private mvpMatrix = mat4.create();
    private modelMatrix = mat4.create();
 
    private vertexPosBuffer: WebGLBuffer;
    private textureCoordBuffer: WebGLBuffer;
    private amountOfVertices: number;
    private texture: WebGLTexture;
 
    public aPositionLocation: number;
    public aTextureCoordLocation: number;
 
    public uMvpMatrixLocation: WebGLUniformLocation;
 
    constructor(vertexBuffers: VertexBuffersCollection, locations: Locations, texture: WebGLTexture)
    {
        this.vertexPosBuffer = vertexBuffers.vertexPosBuffer;
        this.textureCoordBuffer = vertexBuffers.textureCoordBuffer;
        this.amountOfVertices = vertexBuffers.amountOfVertices;
 
        this.aPositionLocation = locations.aPositionLocation;
        this.aTextureCoordLocation = locations.aTextureCoordLocation;
        this.uMvpMatrixLocation = locations.uMvpMatrixLocation;
 
        this.texture = texture;
    }
 
    public draw(gl: WebGLRenderingContext, program: WebGLProgram, viewProjMatrix: mat4): void
    {
        gl.useProgram(program);
 
        gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexPosBuffer);
        gl.vertexAttribPointer(this.aPositionLocation, 3, gl.FLOAT, false, 0, 0);
        gl.enableVertexAttribArray(this.aPositionLocation);
 
        gl.bindBuffer(gl.ARRAY_BUFFER, this.textureCoordBuffer);
        gl.vertexAttribPointer(this.aTextureCoordLocation, 2, gl.FLOAT, false, 0, 0);
        gl.enableVertexAttribArray(this.aTextureCoordLocation);
 
        gl.bindTexture(gl.TEXTURE_2D, this.texture);
 
        mat4.fromTranslation(this.modelMatrix, vec3.fromValues(this.position[0], this.position[1], this.position[2]));
        mat4.rotate(this.modelMatrix, this.modelMatrix, this.angle, [0, 0, 1]);
        mat4.scale(this.modelMatrix, this.modelMatrix, vec3.fromValues(this.scale[0], this.scale[1], this.scale[2]));
 
        mat4.mul(this.mvpMatrix, viewProjMatrix, this.modelMatrix);
        gl.uniformMatrix4fv(this.uMvpMatrixLocation, false, this.mvpMatrix);
        gl.drawArrays(gl.TRIANGLES, 0, this.amountOfVertices);
    }
}
src/client/ObjectForPhysics.ts

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { mat4 } from "gl-matrix";
import * as Matter from "matter-js";
import Locations from "./Locations";
import ObjectForGraphics from "./ObjectForGraphics";
import VertexBuffersCollection from "./VertexBuffersCollection";
 
export default class ObjectForPhysics extends ObjectForGraphics
{
    private _body: Matter.Body
 
    public constructor(body: Matter.Body, vertexBuffers: VertexBuffersCollection, locations: Locations, texture: WebGLTexture)
    {
        super(vertexBuffers, locations, texture);
        this._body = body;
    }
 
    public draw(gl: WebGLRenderingContext, program: WebGLProgram, viewProjMatrix: mat4): void
    {
        this.position[0] = this._body.position.x;
        this.position[1] = this._body.position.y;
        this.angle = this._body.angle;
 
        super.draw(gl, program, viewProjMatrix);
    }
}
src/client/requireConfig.ts

JavaScript
1
2
3
4
5
6
7
8
9
requirejs.config({
    baseUrl: "js",
    paths: {
        "gl-matrix": "https://cdn.jsdelivr.net/npm/gl-matrix@3.3.0/gl-matrix-min",
        "matter-js": "https://cdn.jsdelivr.net/npm/matter-js@0.14.2/build/matter.min"
    }
});
 
requirejs(["main"], () => { });
src/client/shaderProgram.ts

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
export function createShaderProgram(
    gl: WebGLRenderingContext, vertShaderSrc: string, fragShaderSrc: string): WebGLProgram
{
    let ok: boolean;
 
    const vShader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vShader, vertShaderSrc);
    gl.compileShader(vShader);
    ok = gl.getShaderParameter(vShader, gl.COMPILE_STATUS) as boolean;
    if (!ok)
    {
        console.log("Failed to compile the vertex shader:");
        console.log(vertShaderSrc);
    }
 
    const fShader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fShader, fragShaderSrc);
    gl.compileShader(fShader);
    ok = gl.getShaderParameter(fShader, gl.COMPILE_STATUS);
    if (!ok)
    {
        console.log("Failed to compile the fragment shader:");
        console.log(fragShaderSrc);
    }
 
    const program = gl.createProgram();
    gl.attachShader(program, vShader);
    gl.attachShader(program, fShader);
    gl.linkProgram(program);
 
    return program;
}
src/client/textures.ts

JavaScript
1
2
3
4
5
6
7
8
9
10
11
export function createTexture (gl: WebGLRenderingContext, image: HTMLImageElement): WebGLTexture
{
    const texture = gl.createTexture();
 
    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);
 
    return texture;
}
src/client/vertexBuffers.ts

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import VertexBuffersCollection from "./VertexBuffersCollection";
 
export function initVertexBuffers(gl: WebGLRenderingContext, xmlModel: Document) : VertexBuffersCollection
{
    let dataIndexArrray, dataVertPosArray, dataNormalArray, dataTexCoordArray;
    let amountOfAttributes;
    
    const meshChildren = xmlModel.getElementsByTagName("mesh")[0].children;
    for (let i = 0; i < meshChildren.length; i++)
    {
        // console.log(meshChildren[i].getElementsByTagName("float_array")[0].getAttribute("id"));
        const id = meshChildren[i].getAttribute("id");
        if (id !== null && id.match(/-mesh-positions/)) // id.endsWith("-mesh-positions") - lib: es2015
        {
            dataVertPosArray = meshChildren[i].getElementsByTagName("float_array")[0]
                .childNodes[0].nodeValue.trim().split(" ").map(value => { return parseFloat(value); });
        }
        else if (id !== null && id.match(/-mesh-normals/))
        {
            dataNormalArray = meshChildren[i].getElementsByTagName("float_array")[0]
                .childNodes[0].nodeValue.trim().split(" ").map(value => { return parseFloat(value); });
        }
        else if (id !== null && id.match(/-mesh-map-0/))
        {
            dataTexCoordArray = meshChildren[i].getElementsByTagName("float_array")[0]
                .childNodes[0].nodeValue.trim().split(" ").map(value => { return parseFloat(value); });
        }
        else if (meshChildren[i].tagName == "triangles" || meshChildren[i].tagName == "polylist")
        {
            amountOfAttributes = meshChildren[i].getElementsByTagName("input").length;
 
            dataIndexArrray = meshChildren[i].getElementsByTagName("p")[0]
                .childNodes[0].nodeValue.trim().split(" ").map(value => { return parseInt(value); });
        }
    }
 
    // console.log("amountOfAttributes = " + amountOfAttributes);
    // console.log("dataIndexArrray = " + dataIndexArrray);
    // console.log("dataVertPosArray = " + dataVertPosArray);
    // console.log("dataNormalArray = " + dataNormalArray);
    // console.log("dataTexCoordArray = " + dataTexCoordArray);
 
    const v: number[] = []
    const n: number[] = []
    const t: number[] = [];
    let vertPosIndex, normalIndex, texCoordIndex;
 
    for (let i = 0; i < dataIndexArrray.length; i += amountOfAttributes)
    {
        vertPosIndex = dataIndexArrray[i + 0];
 
        v.push(dataVertPosArray[vertPosIndex * 3 + 0]);
        v.push(dataVertPosArray[vertPosIndex * 3 + 1]);
        v.push(dataVertPosArray[vertPosIndex * 3 + 2]);
 
        normalIndex = dataIndexArrray[i + 1];
        n.push(dataNormalArray[normalIndex * 3 + 0]);
        n.push(dataNormalArray[normalIndex * 3 + 1]);
        n.push(dataNormalArray[normalIndex * 3 + 2]);
 
        texCoordIndex = dataIndexArrray[i + 2];
        t.push(dataTexCoordArray[texCoordIndex * 2 + 0]);
        t.push(dataTexCoordArray[texCoordIndex * 2 + 1]);
    }
 
    const vertPosBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vertPosBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(v), gl.STATIC_DRAW);
 
    const normalBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(n), gl.STATIC_DRAW);
 
    const texCoordBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(t), gl.STATIC_DRAW);
 
    const vertexBuffers = new VertexBuffersCollection();
    vertexBuffers.vertexPosBuffer = vertPosBuffer;
    vertexBuffers.textureCoordBuffer = texCoordBuffer;
    vertexBuffers.amountOfVertices = v.length / 3;
 
    return vertexBuffers;
}
src/client/VertexBuffersCollection.ts

JavaScript
1
2
3
4
5
6
export default class VertexBuffersCollection
{
    public vertexPosBuffer: WebGLBuffer;
    public textureCoordBuffer: WebGLBuffer;
    public amountOfVertices: number;
}
package.json

JSON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
  "name": "falling-cyberforum-matterjs-ts",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "debug": "tsc -p tsconfigs/tsconfig.debug.json",
    "compile": "tsc -p tsconfigs/tsconfig.release.json",
    "bundle": "browserify public/js/main.js -o public/js/bundle.js",
    "minify": "uglifyjs public/js/bundle.js -o public/js/bundle.min.js",
    "release": "npm run compile && npm run bundle && npm run minify"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "gl-matrix": "^3.3.0",
    "matter-js": "^0.16.1"
  },
  "devDependencies": {
    "@types/matter-js": "^0.14.10",
    "@types/requirejs": "^2.1.32"
  }
}
tsconfig.json

JSON
1
2
3
4
5
6
7
8
9
{
    "compilerOptions": {
        "target": "ES5",
        "outDir": "../public/js"
    },
    "include": [
        "../src/client/**/*.ts"
    ]
}
tsconfig.debug.json

JSON
1
2
3
4
5
6
7
8
9
10
11
12
13
{
    "extends": "./tsconfig.json",
    "compilerOptions": {
        "module": "AMD",
        "sourceMap": true,
        "types": [
            "requirejs",
            "gl-matrix",
            "matter-js"
        ],
        "moduleResolution": "node"
    }
}
tsconfig.release.json

JSON
1
2
3
4
5
6
7
8
9
10
11
12
13
{
    "extends": "./tsconfig.json",
    "compilerOptions": {
        "module": "CommonJS",
        "sourceMap": false,
        "types": [
            "node"
        ]
    },
    "exclude": [
        "../src/client/requireConfig.ts"
    ]
}
0
9991 / 2963 / 497
Регистрация: 05.10.2013
Сообщений: 8,144
Записей в блоге: 243
14.10.2021, 12:51  [ТС]
Сделал демку с простой скелетной анимацией, импортированной из Blender. Демка написана языке TypeScript с использованием WebGL 1.0. Импортирую 3D модели и анимации из формата .dae (COLLADA) из 3D-редактора Blender. Пока без кода, просто демка.

Запустить демку в браузере
  • Сделал выбор объекта кликом мыши с помощью цветового ID в шейдере
  • Подключил физический движок Ammo.js (Ammo.js - это порт физического С++-движка Bullet)
  • Вывожу текст, который не пиксилируется при приближении. Для этого использую Distance Field из программы Hiero, как показано в уроке от ThinMatrix:
    OpenGL 3D Game Tutorial 33: Distance Field Text Rendering
  • Сделал вращение камеры при зажатом колёсике мыши
  • Сделал приближение и отдаление камеры с помощью вращения колёсика мыши
  • Сделал Skybox (окружение в виде неба)
Миниатюры
Небольшие примеры на WebGL  
1
9991 / 2963 / 497
Регистрация: 05.10.2013
Сообщений: 8,144
Записей в блоге: 243
15.10.2021, 10:43  [ТС]
Содержание:
  1. Исходники из книги "WebGL. Программирование трехмерной графики"
  2. WebGL 1.0. Пример выводит точку красного цвета размером 10 пикселей
  3. Пример выводит точку красного цвета размером 10 пикселей на новом стандарте WebGL 2.0
  4. WebGL 1.0. Передача координаты точки из главной программы в программу вертексного шейдера
  5. WebGL 2.0. Передача координаты точки из главной программы в программу вертексного шейдера
  6. WebGL 1.0. Рисование точек в цикле по кругу по формулам
  7. WebGL 2.0. Рисование точек в цикле по кругу по формулам
  8. WebGL 1.0. Передача цвета точки из главной программы в программу фрагментного шейдера
  9. WebGL 1.0. Передача цвета точки из главной программы в программу фрагментного шейдера
  10. WebGL. 1.0. Рисование точки с применением буферного объекта (VBO - Vertex Buffer Object)
  11. WebGL. 2.0. Рисование одной точки с применением буферного объекта (VBO - Vertex Buffer Object)
  12. WebGL 1.0. Рисование нескольких точек с помощью вертексного буферного объекта (VBO)
  13. WebGL 2.0. Рисование нескольких точек с помощью вертексного буферного объекта (VBO)
  14. WebGL 1.0. Рисование трёх точек с помощью вертексного буферного объекта (VBO)
  15. WebGL 2.0. Рисование трёх точек с помощью вертексного буферного объекта (VBO)
  16. WebGL 1.0. Рисование треугольника с помощью gl.LINE_LOOP
  17. WebGL 2.0. Рисование треугольника с помощью gl.LINE_LOOP
  18. WebGL 1.0. Рисование треугольника с помощью gl.TRIANGLES
  19. WebGL 2.0. Рисование треугольника с помощью gl.TRIANGLES
  20. WebGL 1.0. Передача цвета вершины из главной программы в программу шейдера с помощью VBO
  21. WebGL 2.0. Передача цвета вершины из главной программы в программу шейдера с помощью VBO
  22. WebGL 1.0. Рисование нескольких треугольников со случайными расцветками
  23. WebGL 2.0. Рисование нескольких треугольников со случайными расцветками
  24. WebGL 1.0. Рисование линии с помощью gl.LINES
  25. WebGL 2.0. Рисование линии с помощью gl.LINES
  26. WebGL 1.0. Рисование нескольких линий с помощью gl.LINES
  27. WebGL 2.0. Рисование нескольких линий с помощью gl.LINES
  28. WebGL 1.0. Рисование линий с разными расцветками
  29. WebGL 2.0. Рисование линий с разными расцветками
  30. WebGL 1.0. Рисование ломаной с помощью g.LINE_STRIP
  31. WebGL 2.0. Рисование ломаной с помощью g.LINE_STRIP
  32. WebGL 1.0. Рисование замкнутой ломаной с помощью gl.LINE_LOOP
  33. WebGL 2.0. Рисование замкнутой ломаной с помощью gl.LINE_LOOP
  34. WebGL 1.0. Рисование многоугольника с помощью gl.TRIANGLE_STRIP
  35. WebGL 2.0. Рисование многоугольника с помощью gl.TRIANGLE_STRIP
  36. WebGL 1.0. Рисование многоугольника с помощью gl.TRIANGLE_FAN
  37. WebGL 2.0. Рисование многоугольника с помощью gl.TRIANGLE_FAN
  38. WebGL 1.0. Перемещение квадрата с помощью библиотеки glMatrix
  39. WebGL 2.0. Перемещение квадрата с помощью библиотеки glMatrix
  40. WebGL 1.0. Вращение квадрата с помощью библиотеки glMatrix
  41. WebGL 2.0. Вращение квадрата с помощью библиотеки glMatrix
  42. WebGL 1.0. Масштабирование квадрата с помощью библиотеки glMatrix
  43. WebGL 2.0. Масштабирование квадрата с помощью библиотеки glMatrix
  44. WebGL 1.0. Вращение перед перемещением по клику мыши
  45. WebGL 2.0. Вращение перед перемещением по клику мыши
  46. WebGL 1.0. Вращение после перемещения по клику мыши
  47. WebGL 2.0. Вращение после перемещения по клику мыши
  48. WebGL 1.0. Масштабирование по клику мыши
  49. WebGL 2.0. Масштабирование по клику мыши
  50. WebGL 1.0. Перемещение квадрата с помощью клавиш WASD и клавиш-стрелок
  51. WebGL 2.0. Перенос квадрата с помощью клавиш WASD и клавиш-стрелок
  52. WebGL 1.0. Наложение текстуры на квадрат
  53. WebGL 2.0. Наложение текстуры на квадрат
  54. WebGL 1.0. Анимация вращения
  55. WebGL 2.0. Анимация вращения
  56. Программное рисование кругового узора и других замысловатых математических рисунков
  57. Вывод текста
  58. Математические формулы к сообщению #57
  59. Анимированная стереокартинка на Three.js
  60. Пример рисования треугольника на TypeScript и WebGL 1.0 в объектно-ориентированном стиле
  61. Пример рисования нескольких цветных прямоугольников с использованием: WebGL 1.0, TypeScript, glMatrix, AMD, RequireJS
  62. Прототип игры Змейка, переписанный на TypeScript и WebGL из туториала NoobTuts
  63. Прототип 2D змейки с перспективной камерой. WebGL, glMatrix, TypeScript
  64. Играбельная демка 2D змейки с перспективной камерой
  65. Библиотека графических примитивов и демка со свободной камерой от vxg
  66. Пример написания unit-тестов по методологии TDD на фреймворке Jasmine
  67. Textured Rectangle with Transforms using WebGL 1.0, ES5
  68. Textured Rectangle with Transforms using WebGL 2.0, glMatrix, and TypeScript
  69. Определение клика мыши по фигуре. OpenGL 3.1, C#. WebGL, TypeScript
  70. Пример рисования графика синуса на C# с использованием шейдерного OpenGL 3.0
  71. Понг на TypeScript и WebGL 1.0 из текстового туториала от NoobTuts
  72. Порт игры Bitballoon в 3D на WebGL 1.0 и язык TypeScript
  73. Установка системы координат в 2D
  74. Рисование квадратов, координаты которых считываются из удалённой базы данных MySQL и передаются с сервера через WebSocket
  75. Пример на JavaScript, Python и C++, в которым определяется клик мыши по фигуре любой формы, как в 2D, так и в 3D
  76. Спрайтовая анимация на Canvas API на JavaScript, Python и C++
  77. Использование физического движка Planck.js вместе с TypeScript (Planck.js - это порт физического 2D-движка Box2D)
  78. Использование физического движка Ammo.js вместе с TypeScript (Ammo.js - это порт физического 3D-движка Bullet)
  79. Пример падения кругов с буквами с использованием физического 2D-движка Matter.js, WebGL 1.0 и TypeScript
  80. Демка с простой скелетной анимацией, импортированной из Blender на TypeScript и WebGL 1.0
1
1980 / 836 / 115
Регистрация: 01.10.2012
Сообщений: 5,220
Записей в блоге: 2
15.10.2021, 14:42
А тут уже пошли "непростые примеры" :-)

В общем, как я понял, расчет примерно такой: один чувак хочет заказать крутую интерактивную рекламу своего интернет-магазина (например). И вот тогда мы "собираем" зоопарк из десятка (или больше?) open-sources и дописываем недостающие куски там и сям. Случай возможный, но скорее такой заказ получит компания, а не индивидуал. Уж слишком много всего-всего для одного человека даже с тем что показано, а ведь пока ни моделей, ни текстур, ни анимации. И каждое - тонна работы, а иногда нужны и способности. Боюсь что пытаясь "объять необъятное" Вы просто надорветесь. Да и творчества (не побоюсь этого слова) здесь немного - в основном овладение технологиями.
0
15.10.2021, 16:21  [ТС]

Не по теме:

Igor3D, сегодня утром дата вашей последней активности была - апрель 2018

0
1472 / 827 / 140
Регистрация: 12.10.2013
Сообщений: 5,456
16.10.2021, 00:04
114 пост а ниодного красивого изображения мотивирующего что-то изучать.
0
фрилансер
 Аватар для Алексей1153
6506 / 5756 / 1134
Регистрация: 11.10.2019
Сообщений: 15,404
16.10.2021, 07:53
8Observer8, я смотрю, у тебя постоянные поклонники уже имеются
1
1980 / 836 / 115
Регистрация: 01.10.2012
Сообщений: 5,220
Записей в блоге: 2
16.10.2021, 09:36
Цитата Сообщение от 8Observer8 Посмотреть сообщение
Igor3D, сегодня утром дата вашей последней активности была - апрель 2018
И Вы рассчитывали на спокойную жизнь? Кстати чего Вы на Excalibur921 окрысились? Ну увидел человек красивую картинку, хочет такую же, это совершенно нормальный пользователь. Да и предложения "вполне".

Вот напр как сделать чтобы объект оставлял за собой (красивый) размазанный след? Лупить спрайтами - дело нехитрое, но выглядит пошленько. Эх, прорваться бы к родному fractal noise, нo как? Т.е. для каждой точки (фрагментного шейдера) нужно найти точку на пути/траектории объекта, и время когда объект там был. Дальше раскрутимся. Проблема в том что путей может быть много, и самых разнообразных. И как хранить/искать в калечном GLSL - хз. Вполне себе креативная задачка, конечно нужна подготовка, возможно такие техники уже есть.

Но увы, такие вещи Вас не интересуют, наверно это для Вас "слишком мелко". Вот движок физики - то да. Хотя что с ним делать - без понятия. Чего-то там падает, сыпется, катится - этого все наелись еще в начале нулевых. Рушатся карточные домики, падают кости домино, в коробку сыпятся конфеты, пролом стены и.т.д - это все уже 1000 раз было. Может Вы хотели показать что и на (великом) WebGL это теперь возможно! С этим никто не спорит, ну так что с того? Зачем запрягать движок если нет идей его использования? Так, показать "как мы умеем "собирать"? Вообще с креативом как-то совсем хреновато
2
1472 / 827 / 140
Регистрация: 12.10.2013
Сообщений: 5,456
16.10.2021, 10:09
Боюсь что ТС просто накапает модераторам удалить все конструктивные замечания таких же пользователей форума как и он сам. Почему-то у него тут привилегии над всеми.

Я так понимаю больше половины уроков фактически просто взяты с примеров к книгам? Нарисуйте уже хоть что-то сложней треугольника или куба.

Самое простое точки в 3д. Сделайте им хоть какой-то эффект показывающий что это графика, пример пост 97. Как сделать простейшие слайдеры чтоб пользовать мог хоть что то менять? Пусть слайдер задает форму поверхности к которой точки будут плавно лететь со старой позиции.

Обычно в графике еще со школы или института первых курсов самое простое рисуют фракталы, у вас же ниодного их примера…как так?
Цитата Сообщение от Igor3D Посмотреть сообщение
как сделать чтобы объект оставлял за собой (красивый) размазанный след? Лупить спрайтами - дело нехитрое,
Рендерить анимацию полета объекта из N фреймов в накопительный буфер, на каждом фрейме менять параметры объекта. Уже предлагал такой пример салют пост 104 или фигуры заметания пост 101.
Можно наклепать 100500 вариантов салюта изменяемых десятком слайдеров.


*где-то в аду 3д графики*
Обычный пользователь: ухты opengl…я изучу графику и буду рисовать красивые фракталы налету прям в браузере а потом еще всякие эффекты типа салюты и…

Громогласный голос из тьмы: подвиньте ваш куб влево…

Обычный пользователь: …ээ..что?
А потом я сделаю странные аттракторы или придумаю свои формулы сделаю им свечение будет очень красиво…

Громогласный голос из тьмы: подвиньте ваш куб вправо…

Обычный пользователь: откуда этот голос? Какие кубы? Зачем это мне?
Так а потом я делаю рисование красивых цветков из отрезков и сделаю им свечение всякие эффекты на стыках…да opеngl мне поможет рисовать это быстро.

Громогласный голос из тьмы: чувствуйте ваш куб…подвиньте ваш куб влево…
1
16.10.2021, 10:33  [ТС]

Не по теме:

Igor3D, искренне спасибо, что идей мне накидали.

0
1980 / 836 / 115
Регистрация: 01.10.2012
Сообщений: 5,220
Записей в блоге: 2
17.10.2021, 09:04
Цитата Сообщение от Excalibur921 Посмотреть сообщение
громогласный голос из тьмы: подвиньте ваш куб влево…
Боюсь Вы не вполне себе представляете чего стоит его подвинуть , немного расскажу. Для начала его надо "просто выбрать" - и выясняется что это совсем не просто. У меня было сделано "по Липчаку", но с переходом на Core Progile пришлось переписывать выборку вертексов/фейсов, на что ушло не менее 2 месяцев. Вариант с "color ID" явно неполноценный. Городить software дерево - безыдейно, это уже не OpenGL. Поэтому сделал выборку в геометрическом шейдере(ах), возвращая рез-т с помощью Transform Feedback. Возникает резонный вопрос - а почему "система" не только не предоставляет средств для решения стопудово типовой задачи, но даже не дает внятных рекомендаций?

С "подвинуть" полегче, все-таки Bullet идет с примерами где можно тягать объекты (раньше можно было еще пулять зайцами). Но все равно долбаться не один день. И не два. Так что работу Ваня проделал колоссальную. Другое дело это не имеет никакого "товарного вида" и "не завлекает". Ну видимо "технологии" еще не доросли до уровня чтобв такие вещи делались быстро и четко, "ис каропки", вот и видим "как делается колбаса" (тоже полезно знать)

Добавлено через 18 минут
Цитата Сообщение от Excalibur921 Посмотреть сообщение
Рендерить анимацию полета объекта из N фреймов в накопительный буфер, на каждом фрейме менять параметры объекта. Уже предлагал такой пример салют пост 104 или фигуры заметания пост 101.
Можно наклепать 100500 вариантов салюта изменяемых десятком слайдеров.
Что имеется ввиду под "анимацией полета"? Движущийся объект эмиттит партиклы которые потом рисуются биллбордами/спрайтами? Это популярное, но слабое решение. Недостатки быстро вылезут когда нужен длинный но тонкий "хвост", такая форму потребует слишком много слишком мелких частиц. С "заметанием" - тем более. Думается лучше делать хвост в виде "ленточного червя" - биллбоарда следующего за объектом. При этом, однако, теряются выгоды партиклов - автоматычные эффекты объекма и эмиссии. В общем, тут есть о чем подумать, и это интересно
0
1472 / 827 / 140
Регистрация: 12.10.2013
Сообщений: 5,456
17.10.2021, 11:27
ТС очень не любит когда в его теме не его кубы в html.
Опус с кубом к тому что 100 постов а ТС так и рисует кубы да треугольники.

Цитата Сообщение от Igor3D Посмотреть сообщение
Вариант с "color ID" явно неполноценный.
Это да...каких-то 16 000 000 объектов можно выбрать тупо по цвету в одном кадре. Совершенно бесполезный алгоритм. А если еще внести простейшую иерархию типа
выбрали зеленую стену из кирпичей, назначить всем 16 000 000 кирпичам уникальный цвет. Получается можно выбрать 16 000 000 * N объектов в кадре? Пикселей кадра хватит ?

Цитата Сообщение от Igor3D Посмотреть сообщение
Это популярное, но слабое решение.
По моему стандартное для игр.
Цитата Сообщение от Igor3D Посмотреть сообщение
. Недостатки быстро вылезут когда нужен длинный но тонкий "хвост"
Это про пунктирность изогнутого длинного следа? Так а кто мешает делать много фреймов рендера FPS больше 60? Если есть скил в математике можно досыпать немного матана для адаптивного числа спрайтов проанализировав ломанную на угол между отрезками и их длинну полученною при 60 FPS.

Как тяжелый для рендера вариант можно процедурное генерировать каждую частицу но это сильно кушает FPS…. Пару красивых салютов или 100 салютов? Хотя если вся сцена только 1 салют…

Цитата Сообщение от Igor3D Посмотреть сообщение
биллбоарда следующего за объектом.
https://editor.0lik.ru/flame-painter.html
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
17.10.2021, 11:27

WebGL - глубина отрисовки объектов
Прошу помочь тех кто сталкивался или знает как решить проблему: Суть: есть вращающийся куб с...

Не правильное вращение пирамиды WebGL
Привет. Не могу понять из-за чего пирамида так странно поварачивается. Если долго удержать стрелки...

WebGL, детализация текстуры при приближении
WebGL не совсем OpenGL, но мне бы просто идею узнать. А может кто и с threejs знаком) Натянул...

Технология освещения и нормали. Не могу разобраться (WebGL)
Изучаю WebGL по книге &quot;WebGL программирование трехмерной графики&quot;, вот ссылка на её...

Нужно сделать ёлку на Webgl
Помогите сделать елочку на webgl, может кто делал.


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
120
Ответ Создать тему
Новые блоги и статьи
GitHub Copilot в JetBrains: модель по умолчанию, Fix и контроль MCP
and_y87 12.10.2026
10 октября 2026 года GitHub обновил Copilot для JetBrains: добавил настройки стартовой модели, исправления из диагностики и управление автозапуском MCP. Поддержка IDE 2025. 1 прекращена — требуется. . .
GitHub Copilot в JetBrains: модель по умолчанию, Fix и контроль MCP
and_y87 12.10.2026
10 октября 2026 года GitHub обновил Copilot для JetBrains: добавил настройки стартовой модели, исправления из диагностики и управление автозапуском MCP. Поддержка IDE 2025. 1 прекращена — требуется. . .
День 5 из 28: Codex подсказывает следующий запрос
and_y87 12.10.2026
9 октября 2026 года OpenAI запустила бету Composer predictions — подсказок следующего сообщения в текущем диалоге Codex. Это помощь с формулировкой запроса, а не автоматическое продолжение задачи. . . .
Запустил конкурс "тем и промптов для текстовых квестов созданных почти чисто ИИ"
Adler 06.10.2026
Всем привет! За последние три-четыре дня я создал более 16 текстовых квестовых игр используя преимущественно по одному запросу к ИИ на игру. Мне так понравилось смотреть все ветки/ сцены во всех. . .
ИИ не может найти нужный язык в списке
Supersumestria 05.10.2026
Я ему даю вот такое изображение и прошу найти и подчеркнуть немецкий язык. Возвращает он вот это: https:/ / i. **********/ vqBWLe2. png Нужную строчку в 3й колонке просто выдумал. . Это. . .
Новая последняя моя музыка в SUNO
zorxor 05.10.2026
Здравствуйте, дорогие мои друзья! С большой радостью я хотел бы представить вам свою новую последнею музыку, которую сгенерировала мне по моей просьбе нейросеть SUNO. С уважением, zorxor. Это. . .
Программный домашний кинотеатр
russiannick 27.09.2026
Сподобился на программный домашний кинотеатр. В качестве ЯВУ по традиции выбрал js. В помощники взял Яндекс-Алису. Было создано три зала на разные интересы. исторические и ретро сериал Хичкок. . .
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru