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

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

19.11.2017, 16:43. Показов 55275. Ответов 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
9991 / 2963 / 497
Регистрация: 05.10.2013
Сообщений: 8,134
Записей в блоге: 243
24.08.2024, 21:33  [ТС]
Студворк — интернет-сервис помощи студентам
Алгоритм поиска пути A*

Пример базируется на видео курсе: "Unity 5: 2D Pathfinding by Jesse Freeman"

Препятствия задаются единицами, а пустые ячейки - нулями:

JavaScript
1
2
3
4
5
6
7
const grid = [
    [0, 1, 0, 0, 0],
    [0, 0, 0, 0, 0],
    [0, 1, 0, 1, 0],
    [0, 1, 0, 0, 0],
    [0, 0, 0, 1, 0]
];
Тёмно-красным обозначаются препятствия, синим - путь, а зелёным - пустые ячейки:

Демка в песочнице

Название: 31d1026b48e994f88dc38db5bce2a5a4c17dc483.png
Просмотров: 84

Размер: 241 байт

Ячейки пронумерованы по строкам слева направо. В данном примере, стартовая ячейка имеет номер 0, а конечная ячейка - номер 24.

В консоль выводятся:
  • длина пути
  • количество итераций
  • массив ячеек пути. Например, ячейка в массиве ячеек хранит координаты (x, y)

JavaScript
1
2
3
4
console.log("Search done.");
console.log("Path length:", search.path.length);
console.log("Iterations:", search.iterations);
console.log("Path:", search.path);
Вывод в консоль:

Search done.
Path length: 9
Iterations: 25
Path: Array(9)
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
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
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
<!DOCTYPE html>
 
<html lang="en">
 
<head>
    <title>Example</title>
</head>
 
<body>
    <canvas id="renderCanvas" width="300" height="300"></canvas>
 
    <script id="vertexShader" type="x-shader/x-vertex">
        attribute vec2 aPosition;
        uniform mat4 uMvpMatrix;
 
        void main() {
            gl_Position = uMvpMatrix * vec4(aPosition, 0.0, 1.0);
        }
    </script>
 
    <script id="fragmentShader" type="x-shader/x-fragment">
        precision mediump float;
        uniform vec3 uColor;
 
        void main() {
            gl_FragColor = vec4(uColor, 1.0);
        }
    </script>
 
    <script type="importmap">
        {
            "imports": {
                "gl-matrix": "https://cdn.skypack.dev/gl-matrix@3.4.3"
            }
        }
    </script>
 
    <script type="module">
        import { mat4, vec3, glMatrix } from "gl-matrix";
 
        let gl, program, uMvpMatrixLocation, uColorLocation;
 
        const modelMatrix = mat4.create();
        const mvpMatrix = mat4.create();
 
        const projMatrix = mat4.create();
        mat4.ortho(projMatrix, -0.5, 4.5, 4.5, -0.5, 10, -10);
 
        const viewMatrix = mat4.create();
        mat4.lookAt(viewMatrix, [0, 0, 10], [0, 0, 0], [0, 1, 0]);
 
        const projViewMatrix = mat4.create();
        mat4.mul(projViewMatrix, projMatrix, viewMatrix);
 
        const grid = [
            [0, 1, 0, 0, 0],
            [0, 0, 0, 0, 0],
            [0, 1, 0, 1, 0],
            [0, 1, 0, 0, 0],
            [0, 0, 0, 1, 0]
        ];
        let search;
 
        function createShaderProgram(vertShaderElementId, fragShaderElementId) {
            const vShader = gl.createShader(gl.VERTEX_SHADER);
            const vShaderSrc = document.getElementById(vertShaderElementId)
                .firstChild.textContent;
            gl.shaderSource(vShader, vShaderSrc);
            gl.compileShader(vShader);
            let ok = gl.getShaderParameter(vShader, gl.COMPILE_STATUS);
            if (!ok) {
                console.log("vert: " + gl.getShaderInfoLog(vShader));
                return null;
            };
 
            const fShader = gl.createShader(gl.FRAGMENT_SHADER);
            const fShaderSrc = document.getElementById(fragShaderElementId)
                .firstChild.textContent;
            gl.shaderSource(fShader, fShaderSrc);
            gl.compileShader(fShader);
            ok = gl.getShaderParameter(fShader, gl.COMPILE_STATUS);
            if (!ok) {
                console.log("frag: " + gl.getShaderInfoLog(fShader));
                return null;
            };
 
            const program = gl.createProgram();
            gl.attachShader(program, vShader);
            gl.attachShader(program, fShader);
            gl.linkProgram(program);
            ok = gl.getProgramParameter(program, gl.LINK_STATUS);
            if (!ok) {
                console.log("link: " + gl.getProgramInfoLog(program));
            };
            gl.useProgram(program);
 
            return program;
        }
 
        function initWebGLContext(canvasName) {
            const canvas = document.getElementById(canvasName);
            if (canvas === null) {
                console.log(`Failed to get a canvas element with the name "${canvasName}"`);
                return false;
            }
            gl = canvas.getContext("webgl", { alpha: false, premultipliedAlpha: false });
            return true;
        }
 
        function drawRect(pos, scale, color, angle = 0) {
            mat4.fromTranslation(modelMatrix, pos);
            mat4.rotateZ(modelMatrix, modelMatrix, glMatrix.toRadian(angle));
            mat4.scale(modelMatrix, modelMatrix, scale);
            mat4.mul(mvpMatrix, projViewMatrix, modelMatrix);
            gl.uniformMatrix4fv(uMvpMatrixLocation, false, mvpMatrix);
            gl.uniform3fv(uColorLocation, color);
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
        }
 
        function draw() {
            gl.clearColor(0.9, 0.9, 0.95, 1);
            gl.clear(gl.COLOR_BUFFER_BIT);
 
            const obstacleColor = vec3.fromValues(0.5, 0, 0);
            const emptyFieldColor = vec3.fromValues(0.3, 0.9, 0.3);
            const rows = grid.length;
            const cols = grid[0].length;
            for (let r = 0; r < cols; r++) {
                for (let c = 0; c < cols; c++) {
                    if (grid[r][c] === 0) {
                        drawRect(vec3.fromValues(c, r, 0), vec3.fromValues(0.9, 0.9, 1), emptyFieldColor);
                    } else if (grid[r][c] === 1) {
                        drawRect(vec3.fromValues(c, r, 0), vec3.fromValues(0.9, 0.9, 1), obstacleColor);
                    }
                }
            }
 
            const pathColor = vec3.fromValues(0, 0, 0.5);
            search.path.forEach(node => {
                drawRect(vec3.fromValues(node.x, node.y, 0), vec3.fromValues(0.9, 0.9, 1), pathColor);
            });
        }
 
        class Node {
            constructor() {
                this.adjacents = [];
                this.previous = null;
                this.label = "";
            }
 
            clear() {
                this.previous = null;
            }
        }
 
        class Graph {
            constructor(grid) {
                this.rows = grid.length;
                this.cols = grid[0].length;
                this.nodes = [];
                for (let i = 0; i < this.rows * this.cols; i++) {
                    const node = new Node();
                    node.label = i.toString();
                    this.nodes[i] = node;
                }
 
                for (let r = 0; r < this.rows; r++) {
                    for (let c = 0; c < this.cols; c++) {
                        const node = this.nodes[this.cols * r + c];
                        node.y = r;
                        node.x = c;
 
                        if (grid[r][c] === 1) {
                            continue;
                        }
 
                        // Up
                        if (r > 0) {
                            node.adjacents.push(this.nodes[this.cols * (r - 1) + c]);
                        }
 
                        // Right
                        if (c < this.cols - 1) {
                            node.adjacents.push(this.nodes[this.cols * r + c + 1]);
                        }
 
                        // Down
                        if (r < this.rows - 1) {
                            node.adjacents.push(this.nodes[this.cols * (r + 1) + c]);
                        }
 
                        // Left
                        if (c > 0) {
                            node.adjacents.push(this.nodes[this.cols * r + c - 1]);
                        }
                    }
                }
                // console.log(this.nodes);
            }
        }
 
        // Returns a random integer between min (inclusive) and max (inclusive)
        function getRandomInt(min, max) {
            min = Math.ceil(min);
            max = Math.floor(max);
            return Math.floor(Math.random() * (max - min + 1)) + min;
        }
 
        class Search {
            constructor(graph) {
                this.graph = graph;
                this.finished = false;
            }
 
            start(startNode, goalNode) {
                this.reachables = [];
                this.reachables.push(startNode);
                this.goalNode = goalNode;
                this.explored = [];
                this.path = [];
                this.iterations = 0;
 
                for (let i = 0; i < this.graph.nodes.length; i++) {
                    this.graph.nodes[i].clear();
                }
            }
 
            step() {
                if (this.path.length > 0) {
                    return;
                }
 
                if (this.reachables.length === 0) {
                    this.finished = true;
                    return;
                }
 
                this.iterations++;
 
                let node = this.choseNode();
                if (node === this.goalNode) {
                    while (node !== null) {
                        this.path.splice(0, 0, node);
                        node = node.previous;
                    }
                    this.finished = true;
                    return;
                }
 
                const index = this.reachables.indexOf(node);
                if (index > -1) {
                    this.reachables.splice(index, 1);
                    this.explored.push(node);
 
                    for (let i = 0; i < node.adjacents.length; i++) {
                        this.addAdjacent(node, node.adjacents[i]);
                    }
                }
            }
 
            addAdjacent(node, adjacent) {
                if (this.findNode(adjacent, this.explored) ||
                    this.findNode(adjacent, this.reachables)) {
                    return;
                }
 
                adjacent.previous = node;
                this.reachables.push(adjacent);
            }
 
            findNode(node, list) {
                return list.indexOf(node) >= 0;
            }
 
            /*
            getNodeIndex(node, list) {
                for (let i = 0; i < list.length; i++) {
                    if (node === list[i]) {
                        return i;
                    }
                }
 
                return -1;
            }
            */
 
            choseNode() {
                return this.reachables[getRandomInt(0, this.reachables.length - 1)];
            }
        }
 
        function main() {
            if (!initWebGLContext("renderCanvas")) return;
 
            program = createShaderProgram("vertexShader", "fragmentShader");
 
            const vertPositions = [
                -0.5, -0.5,
                -0.5, 0.5,
                0.5, -0.5,
                0.5, 0.5
            ];
            const vertPosBuffer = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, vertPosBuffer);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertPositions), gl.STATIC_DRAW);
            const aPositionLocation = gl.getAttribLocation(program, "aPosition");
            gl.vertexAttribPointer(aPositionLocation, 2, gl.FLOAT, false, 0, 0);
            gl.enableVertexAttribArray(aPositionLocation);
 
            uMvpMatrixLocation = gl.getUniformLocation(program, "uMvpMatrix");
            uColorLocation = gl.getUniformLocation(program, "uColor");
 
            // s 0 0
            // 0 1 1
            // 0 0 f
            /*
            const grid = [
                [0, 0, 0],
                [0, 1, 1],
                [0, 0, 0]
            ];
            */
 
            /*
            const grid = [];
            grid[0] = [];
            grid[1] = [];
            grid[2] = [];
            grid[0][0] = { x: 1, y: 1 };
            grid[0][1] = { x: 1, y: 2 };
            grid[0][2] = { x: 1, y: 2 };
            grid[1][0] = { x: 1, y: 2 };
            grid[1][1] = { x: 1, y: 2 };
            grid[1][2] = { x: 1, y: 2 };
            */
            const graph = new Graph(grid);
            search = new Search(graph);
            search.start(graph.nodes[0], graph.nodes[24]);
 
            while (!search.finished) {
                search.step();
            }
            console.log("Search done.");
            console.log("Path length:", search.path.length);
            console.log("Iterations:", search.iterations);
            console.log("Path:", search.path);
            draw();
        }
 
        main();
    </script>
</body>
 
</html>
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
24.08.2024, 21:33

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

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
201
Ответ Создать тему
Новые блоги и статьи
Nekobox - outbounds[0].transport: unknown transport type: raw
damix 01.10.2026
Фикс ошибки Правым кликом по серверу -> отладочная информация -> edit Заменить "net": "raw", на "net": "tcp", Нажать кнопку reload.
Программный домашний кинотеатр
russiannick 27.09.2026
Сподобился на программный домашний кинотеатр. В качестве ЯВУ по традиции выбрал js. В помощники взял Яндекс-Алису. Было создано три зала на разные интересы. исторические и ретро сериал Хичкок. . .
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
Программа опроса у.з. расходомера SLS-720F
Argus19 02.09.2026
Программа опроса у. з. расходомера SLS-720F Программа опрашивает один раз в минуту три ультразвуковых расходомера SLS-720F через интерфейс RS-485 по протоколу Modbus RTU. Опрашиваются регистры. . .
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru