Форум программистов, компьютерный форум, киберфорум
JavaScript: HTML5 Canvas
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 5.00/1: Рейтинг темы: голосов - 1, средняя оценка - 5.00
403 / 19 / 5
Регистрация: 17.01.2017
Сообщений: 572

Похожая функция drawTriangles(flash) в html5?

29.08.2023, 22:59. Показов 3331. Ответов 21
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Мне нужно перевести код Flash в html5, не знаю какая альтернативная функция drawTriangles, есть в html5. Вот функция flash.
ActionScript 3
1
2
graphics.drawTriangles(Vector.<Number>([0, 0, width1, 0, 0, height1]),// вектор вершин расположение по x и y
                       Vector.<int>([0, 2, 1])); // вектор с индексами этих вершин
Первый параметр это координаты вершин. Второй параметр индекс этих вершин [0,2,1]. Каждое значение индекса ссылается на вектор по x и y, например
0-индекс ссылается на точку (0,0).
2 – ссылается на точку (0,height1)
1 – на точку (width1,0), таким образом из общей картинки отображается только часть, в нашем случае треугольник.

Как перевести код flash на html5, альтернатива drawTriangles(flash)?

Полностью код на flash.
ActionScript 3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package
{
  import flash.display.Sprite;
  import flash.display.BitmapData;
  import flash.display.Bitmap;
  public class Main extends Sprite
  {
        var archer1:BitmapData = new archer(0, 0);
        var width1:int = 350;
        var height1:int = 200;
 
        public function Main():void
        {
            var bitmap:Bitmap = new Bitmap(archer1);
            
            graphics.beginBitmapFill(bitmap.bitmapData)
            graphics.lineStyle(1, 0x999999);
            
            
            graphics.drawTriangles(Vector.<Number>([0, 0, width1, 0, 0, height1]),// вектор вершин расположение по x и y
                       Vector.<int>([0, 2, 1])); // вектор с индексами этих вершин
        }
  }
}
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
29.08.2023, 22:59
Ответы с готовыми решениями:

Функция похожая на memcmp
Мне нужна функция, похожая на memcmp, но возвращающая номер первого несовпадающего байта. Есть ли такая в стандартных библиотеках? ...

Функция похожая на ShowModal
Приветствую всех. Как известно, у формы есть метод ShowModal. Он показывает форму и не возвращает значение, пока форма не закроется. Мне...

window похожая функция
есть какая-то функция на visual studio типа window очень надо

21
 Аватар для NTHing
1782 / 963 / 388
Регистрация: 26.11.2014
Сообщений: 1,966
Записей в блоге: 1
12.09.2023, 16:03
Такое если...
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 <div class="image-container">
      <img class="clipped-image" src="myImage.jpg"/>
    </div>
    <style>
      .image-container {
        width: 300px;
        height: 200px;
      }
      .clipped-image {
        width: 100%;
        height: 100%;
        clip-path: polygon(0% 0%, 50% 0%, 0% 50%);
      }
    </style>
0
9945 / 2946 / 496
Регистрация: 05.10.2013
Сообщений: 8,016
Записей в блоге: 241
24.06.2024, 22:00
У элемента <canvas> кроме контекста "2d" есть контекст "webgl". Таким образом это контекст можно получить:

JavaScript
1
2
        const canvas = document.getElementById("renderCanvas");
        const gl = canvas.getContext("webgl");
В следующем примере получаем контекст, выставляем цвет заливки (gl.clearColor) и выполняем заливку (gl.clear):

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
<!DOCTYPE html>
 
<html>
 
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Get WebGL context</title>
</head>
 
<body>
    <canvas id="renderCanvas" width="350" height="350"></canvas>
 
    <script type="module">
        const canvas = document.getElementById("renderCanvas");
        const gl = canvas.getContext("webgl");
 
        gl.clearColor(48 / 255, 56 / 255, 65 / 255, 1);
        gl.clear(gl.COLOR_BUFFER_BIT);
    </script>
</body>
 
</html>
Следующий пример рисует треугольник: https://plnkr.co/edit/N4S9FGWtmll3VaUc?preview

Исходники

index.html

PHP/HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
 
<html>
 
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Simple triangle using WebGL 1.0 and JavaScript</title>
</head>
 
<body>
    <canvas id="renderCanvas" width="350" height="350"></canvas>
    <script type="module" src="./js/index.js"></script>
</body>
 
</html>
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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import { gl, initWebGLContext } from "./webgl-context.js";
import createProgram from "./shader-program.js";
 
let aPositionLocation, vertPosBuffer;
 
async function init() {
    if (!initWebGLContext("renderCanvas")) {
        return;
    }
 
    const shaderProgram = await createProgram("assets/shaders/",
        "color.vert", "color.frag");
 
    const vertPositions = [
        -0.5, -0.5,
        0.5, -0.5,
        0, 0.5
    ];
    vertPosBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vertPosBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertPositions), gl.STATIC_DRAW);
    // Set up the position attribute
    aPositionLocation = gl.getAttribLocation(shaderProgram, "aPosition");
 
    gl.clearColor(48 / 255, 56 / 255, 65 / 255, 1);
    draw();
}
 
init();
 
function draw() {
    gl.clear(gl.COLOR_BUFFER_BIT);
 
    gl.bindBuffer(gl.ARRAY_BUFFER, vertPosBuffer);
    gl.vertexAttribPointer(aPositionLocation, 2, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(aPositionLocation);
 
    gl.drawArrays(gl.TRIANGLES, 0, 3)
}
shader-program.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
43
import { gl } from "./webgl-context.js";
 
export default async function createProgram(path, vertShaderFileName,
    fragShaderFileName) //
{
    let response = await fetch(path + vertShaderFileName);
    const vertShaderSource = await response.text();
    response = await fetch(path + fragShaderFileName);
    const fragShaderSource = await response.text();
 
    const vShader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vShader, vertShaderSource);
    gl.compileShader(vShader);
    let ok = gl.getShaderParameter(vShader, gl.COMPILE_STATUS);
    if (!ok) {
        console.log(`${vertShaderFileName}: ${gl.getShaderInfoLog(vShader)}`);
        return null;
    };
 
    const fShader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fShader, fragShaderSource);
    gl.compileShader(fShader);
    ok = gl.getShaderParameter(fShader, gl.COMPILE_STATUS);
    if (!ok) {
        console.log(`${fragShaderFileName}: ${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 error with shaders ${vertShaderFileName}` +
            ` and ${fragShaderFileName}`);
        console.log(gl.getProgramInfoLog(program));
        return null;
    };
    gl.useProgram(program);
 
    return program;
}
webgl-context.js

JavaScript
1
2
3
4
5
6
7
8
9
10
11
export let gl = null;
 
export 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;
}
color.vert

glSlang
1
2
3
4
5
6
attribute vec2 aPosition;
 
void main()
{
    gl_Position = vec4(aPosition, 0.0, 1.0);
}
color.frag

glSlang
1
2
3
4
5
6
precision mediump float;
 
void main()
{
    gl_FragColor = vec4(0.2, 0.7, 0.3, 1.0);
}




Миниатюры
0
9945 / 2946 / 496
Регистрация: 05.10.2013
Сообщений: 8,016
Записей в блоге: 241
24.06.2024, 22:08
Пример рисования повёрнутого прямоугольника на WebGL: https://plnkr.co/edit/rOIrHBskyz3JTw2s?preview

Исходники

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
<!DOCTYPE html>
 
<html>
 
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Transformed rectangle using WebGL 1.0 and JavaScript</title>
</head>
 
<body>
    <canvas id="renderCanvas" width="350" height="350"></canvas>
 
    <script type="importmap">
        {
            "imports": {
                "gl-matrix": "https://8observer8.github.io/libs/gl-matrix@3.4.3/gl-matrix.min.js"
            }
        }
    </script>
 
    <script type="module" src="./js/index.js"></script>
</body>
 
</html>
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
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 { glMatrix, mat4, vec3 } from "gl-matrix";
import { gl, initWebGLContext } from "./webgl-context.js";
import createProgram from "./shader-program.js";
 
let aPositionLocation, uMvpMatrixLocation, vertPosBuffer;
 
// Set up the model-view-projection matrix
const mvpMatrix = mat4.create();
const modelMatrix = mat4.create();
const viewMatrix = mat4.create();
const projMatrix = mat4.create();
const projViewMatrix = mat4.create();
mat4.ortho(projMatrix, 0, 100, 0, 100, 1, -1);
mat4.lookAt(viewMatrix, [0, 0, 1], [0, 0, 0], [0, 1, 0]);
 
async function init() {
    if (!initWebGLContext("renderCanvas")) {
        return;
    }
 
    const shaderProgram = await createProgram("assets/shaders/",
        "color.vert", "color.frag");
 
    const vertPositions = [
        -0.5, -0.5,
        0.5, -0.5,
        -0.5, 0.5,
        0.5, 0.5
    ];
    vertPosBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vertPosBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertPositions), gl.STATIC_DRAW);
    // Set up the position attribute
    aPositionLocation = gl.getAttribLocation(shaderProgram, "aPosition");
 
    uMvpMatrixLocation = gl.getUniformLocation(shaderProgram, "uMvpMatrix");
 
    gl.clearColor(0.188, 0.22, 0.255, 1);
    draw();
}
 
init();
 
function draw() {
    gl.clear(gl.COLOR_BUFFER_BIT);
 
    gl.bindBuffer(gl.ARRAY_BUFFER, vertPosBuffer);
    gl.vertexAttribPointer(aPositionLocation, 2, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(aPositionLocation);
 
    mat4.identity(modelMatrix);
    mat4.mul(projViewMatrix, projMatrix, viewMatrix);
    mat4.translate(modelMatrix, modelMatrix, [50, 50, 0]);
    mat4.rotateZ(modelMatrix, modelMatrix, glMatrix.toRadian(10));
    mat4.scale(modelMatrix, modelMatrix, [80, 10, 1]);
    mat4.mul(mvpMatrix, projViewMatrix, modelMatrix);
    gl.uniformMatrix4fv(uMvpMatrixLocation, false, mvpMatrix);
    gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4)
}
shader-program.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
43
import { gl } from "./webgl-context.js";
 
export default async function createProgram(path, vertShaderFileName,
    fragShaderFileName) //
{
    let response = await fetch(path + vertShaderFileName);
    const vertShaderSource = await response.text();
    response = await fetch(path + fragShaderFileName);
    const fragShaderSource = await response.text();
 
    const vShader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vShader, vertShaderSource);
    gl.compileShader(vShader);
    let ok = gl.getShaderParameter(vShader, gl.COMPILE_STATUS);
    if (!ok) {
        console.log(`${vertShaderFileName}: ${gl.getShaderInfoLog(vShader)}`);
        return null;
    };
 
    const fShader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fShader, fragShaderSource);
    gl.compileShader(fShader);
    ok = gl.getShaderParameter(fShader, gl.COMPILE_STATUS);
    if (!ok) {
        console.log(`${fragShaderFileName}: ${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 error with shaders ${vertShaderFileName}` +
            ` and ${fragShaderFileName}`);
        console.log(gl.getProgramInfoLog(program));
        return null;
    };
    gl.useProgram(program);
 
    return program;
}
webgl-context.js

JavaScript
1
2
3
4
5
6
7
8
9
10
11
export let gl = null;
 
export 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;
}
color.vert

glSlang
1
2
3
4
5
6
7
8
attribute vec2 aPosition;
 
uniform mat4 uMvpMatrix;
 
void main()
{
    gl_Position = uMvpMatrix * vec4(aPosition, 0.0, 1.0);
}
color.frag

glSlang
1
2
3
4
5
6
precision mediump float;
 
void main()
{
    gl_FragColor = vec4(0.2, 0.7, 0.3, 1.0);
}




Миниатюры
0
9945 / 2946 / 496
Регистрация: 05.10.2013
Сообщений: 8,016
Записей в блоге: 241
25.06.2024, 01:37
Если заинтересует WebGL, то в этой теме есть туториал.
0
9945 / 2946 / 496
Регистрация: 05.10.2013
Сообщений: 8,016
Записей в блоге: 241
25.06.2024, 12:54
Несколько слов о том, как работают шейдеры. Их два: вершинный и фрагментный (или пиксельный). Вершинный отвечает за расстановку вершин треугольников, а пиксельный за покраску пикселей:

Вершинный шейдер:

glSlang
1
2
3
4
5
6
7
8
attribute vec2 aPosition;
 
uniform mat4 uMvpMatrix;
 
void main()
{
    gl_Position = uMvpMatrix * vec4(aPosition, 0.0, 1.0);
}
Фрагментный шейдер:

glSlang
1
2
3
4
5
6
precision mediump float;
 
void main()
{
    gl_FragColor = vec4(0.2, 0.7, 0.3, 1.0);
}
В мире компьютерной графики на WebGL главенструет линейная алгебра, поэтому важно подключить библиотеку для работы с матрицами и векторами:

PHP/HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
<body>
    <canvas id="renderCanvas" width="350" height="350"></canvas>
 
    <script type="importmap">
        {
            "imports": {
                "gl-matrix": "https://8observer8.github.io/libs/gl-matrix@3.4.3/gl-matrix.min.js"
            }
        }
    </script>
 
    <script type="module" src="./js/index.js"></script>
</body>
В примере с трансформированным прямоугольником используются три матрицы:

1) Матрица проекции. Она задаёт размеры мира по трём осям: X, Y, Z. Задаёт диапазонами. Сначала идёт диапазон по X, потом по Y, а потом по Z. В следующим коде размер мира по X от 0 до 100, размер мира по Y от 0 до 100, а размер мира по Z от 1 до -1. Ось Z смотрит на наблюдателя:

JavaScript
1
2
const projMatrix = mat4.create();
mat4.ortho(projMatrix, 0, 100, 0, 100, 1, -1);
2) Матрица вида. Эта матрица задаёт позицию набладателя в пространстве, точку наблюдения и направление макушки наблюдателя. Обычно макушка наблюателя направлена вверх по Y: (0, 1, 0)

JavaScript
1
2
const viewMatrix = mat4.create();
mat4.lookAt(viewMatrix, [0, 0, 1], [0, 0, 0], [0, 1, 0]);
3) Матрица модели или модельная матрица. Эта матрица отвечает за позицию, вращение и размер объекта. Например, следующая матрица модели задаёт квадрату размером 1x1 позицию, размер (делая из него прямоугольник) и поворот вокруг оси Z:

JavaScript
1
2
3
mat4.translate(modelMatrix, modelMatrix, [50, 50, 0]);
mat4.rotateZ(modelMatrix, modelMatrix, glMatrix.toRadian(10));
mat4.scale(modelMatrix, modelMatrix, [80, 10, 1]);
Перед отправкой в шейдер матрицы должны быть перемножены:

JavaScript
1
2
mat4.mul(projViewMatrix, projMatrix, viewMatrix);
mat4.mul(mvpMatrix, projViewMatrix, modelMatrix);
В командах выше умножение матриц работает следующим образом: projMatrix умножается на viewMatrix и результат умножения сохраняется в projViewMatrix.

В шейдер отправляется итоговая MVP (Model-view-projection) матрица следующей командой:

JavaScript
1
gl.uniformMatrix4fv(uMvpMatrixLocation, false, mvpMatrix);
Определение квадрата и отправка его в память видео карты

Следующем образом происходит определение вершин для квадрата и отправка его в память видео карты. Это делается один раз во время инициализации программы:

JavaScript
1
2
3
4
5
6
7
8
9
    const vertPositions = [
        -0.5, -0.5,
        0.5, -0.5,
        -0.5, 0.5,
        0.5, 0.5
    ];
    vertPosBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vertPosBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertPositions), gl.STATIC_DRAW);
Я использую способ TRIANGLE_STRIP для определения последовательности вершин:



Вершины квадрата и MVP-матрица переданы. Для запуска процесса рисования с помощью шейдеров вызывается метод:

JavaScript
1
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
В нём передаётся способ рисования (TRIANGLE_STRIP), номер нулевой вершины и количество вершин, которы надо отобразить.

Вершинный шейдер будет вызван 4 раза. Каждый раз он будет брать из массива вершин одну вершину и умножать MVP-матрицу на эту вершину. Таким образом он расставит вершины. Далее, перед вызовом фрагментного шейдера каждый треугольник (а их 2 в прямоугольнике) будет разбит на фрагменты (грубо говоря пиксели) и будет создан внутри видеокарты массив фрагментов. Фрагментный шейдер будет вызван последовательно для каждого фрагмента и каждому фрагменту будет присвоен заданный цвет. На самом деле программа фрагментного шейдера будет запущена на множестве потоков одновременно, то есть покраска фрагментов будет происходит параллельно для множетства фрагментов.

Миниатюры
0
9945 / 2946 / 496
Регистрация: 05.10.2013
Сообщений: 8,016
Записей в блоге: 241
25.06.2024, 14:09
У WebGL есть преимущество перед Phaser и Pixi.js в том, что WebGL относительно нетрудно переписать на С++ и OpenGL (для окна можно взять: Qt, SDL, GLFW и т.д.), чтобы создать EXE. Либо переписать на Python (для окна можно взять: PyQt, PySide, PySDL и т.д.)

Например, трансформированный прямоугольник на C++ и Python:

Использование QOpenGLWidget для окна


PyQt6


main.py

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
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
import sys
 
import numpy as np
from OpenGL.GL import (GL_COLOR_BUFFER_BIT, GL_FLOAT, GL_TRIANGLE_STRIP,
                       glClear, glClearColor, glDrawArrays)
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QMatrix4x4, QSurfaceFormat, QVector3D
from PyQt6.QtOpenGL import QOpenGLBuffer, QOpenGLShader, QOpenGLShaderProgram
from PyQt6.QtOpenGLWidgets import QOpenGLWidget
from PyQt6.QtWidgets import QApplication
 
 
class OpenGLWidget(QOpenGLWidget):
 
    def __init__(self):
        super().__init__()
 
        self.setWindowTitle("OpenGL ES 2.0, PyQt6, Python")
        self.initialWindowWidth = 380
        self.initialWindowHeight = 380
        self.resize(self.initialWindowWidth, self.initialWindowHeight)
        self.worldWidth = 100
        self.worldHeight = 100
 
        surfaceFormat = QSurfaceFormat()
        surfaceFormat.setDepthBufferSize(24)
        surfaceFormat.setSamples(4)
        self.setFormat(surfaceFormat)
 
    def initializeGL(self):
        glClearColor(0.188, 0.22, 0.255, 1)
 
        vertShaderSrc = """
            attribute vec2 aPosition;
            uniform mat4 uMvpMatrix;
            void main()
            {
                gl_Position = uMvpMatrix * vec4(aPosition, 0.0, 1.0);
            }
        """
 
        fragShaderSrc = """
            #ifdef GL_ES
            precision mediump float;
            #endif
            void main()
            {
                gl_FragColor = vec4(0.2, 0.7, 0.3, 1.0);
            }
        """
 
        self.program = QOpenGLShaderProgram()
        self.program.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Vertex, vertShaderSrc)
        self.program.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Fragment, fragShaderSrc)
        self.program.link()
        self.program.bind()
 
        vertPositions = np.array([
            -0.5, -0.5,
            0.5, -0.5,
            -0.5, 0.5,
            0.5, 0.5], dtype=np.float32)
        self.vertPosBuffer = QOpenGLBuffer()
        self.vertPosBuffer.create()
        self.vertPosBuffer.bind()
        self.vertPosBuffer.allocate(vertPositions, len(vertPositions) * 4)
        self.program.setAttributeBuffer("aPosition", GL_FLOAT, 0, 2)
        self.program.enableAttributeArray("aPosition")
 
        self.uMvpMatrixLocation = self.program.uniformLocation("uMvpMatrix")
 
        self.viewMatrix = QMatrix4x4()
        self.viewMatrix.lookAt(QVector3D(0, 0, 1), QVector3D(0, 0, 0),
            QVector3D(0, 1, 0))
 
        self.projMatrix = QMatrix4x4()
        self.projViewMatrix = QMatrix4x4()
        self.modelMatrix = QMatrix4x4()
        self.mvpMatrix = QMatrix4x4()
 
    def resizeGL(self, w, h):
        coofWidth = w / self.initialWindowWidth
        coofHeight = h / self.initialWindowHeight
 
        self.projMatrix.setToIdentity()
        self.projMatrix.ortho(0, self.worldWidth * coofWidth,
            0, self.worldHeight * coofHeight, 1, -1)
        self.projViewMatrix = self.projMatrix * self.viewMatrix
 
    def paintGL(self):
        self.program.bind()
        glClear(GL_COLOR_BUFFER_BIT)
        self.modelMatrix.setToIdentity()
        self.modelMatrix.translate(QVector3D(50, 50, 0))
        self.modelMatrix.rotate(10, QVector3D(0, 0, 1))
        self.modelMatrix.scale(QVector3D(80, 10, 1))
        self.mvpMatrix = self.projViewMatrix * self.modelMatrix
        self.program.setUniformValue(self.uMvpMatrixLocation, self.mvpMatrix)
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)
 
if __name__ == "__main__":
    QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL)
    app = QApplication(sys.argv)
    w = OpenGLWidget()
    w.show()
    sys.exit(app.exec())


PySide6

main.py

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
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
import sys
 
import numpy as np
from OpenGL.GL import (GL_COLOR_BUFFER_BIT, GL_FLOAT, GL_TRIANGLE_STRIP,
                       glClear, glClearColor, glDrawArrays)
from PySide6.QtCore import Qt
from PySide6.QtGui import QMatrix4x4, QSurfaceFormat, QVector3D
from PySide6.QtOpenGL import QOpenGLBuffer, QOpenGLShader, QOpenGLShaderProgram
from PySide6.QtOpenGLWidgets import QOpenGLWidget
from PySide6.QtWidgets import QApplication
 
 
class OpenGLWidget(QOpenGLWidget):
 
    def __init__(self):
        super().__init__()
 
        self.setWindowTitle("OpenGL ES 2.0, PySide6, Python")
        self.initialWindowWidth = 380
        self.initialWindowHeight = 380
        self.resize(self.initialWindowWidth, self.initialWindowHeight)
        self.worldWidth = 100
        self.worldHeight = 100
 
        surfaceFormat = QSurfaceFormat()
        surfaceFormat.setDepthBufferSize(24)
        surfaceFormat.setSamples(4)
        self.setFormat(surfaceFormat)
 
    def initializeGL(self):
        glClearColor(0.188, 0.22, 0.255, 1)
 
        vertShaderSrc = """
            attribute vec2 aPosition;
            uniform mat4 uMvpMatrix;
            void main()
            {
                gl_Position = uMvpMatrix * vec4(aPosition, 0.0, 1.0);
            }
        """
 
        fragShaderSrc = """
            #ifdef GL_ES
            precision mediump float;
            #endif
            void main()
            {
                gl_FragColor = vec4(0.2, 0.7, 0.3, 1.0);
            }
        """
 
        self.program = QOpenGLShaderProgram()
        self.program.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Vertex, vertShaderSrc)
        self.program.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Fragment, fragShaderSrc)
        self.program.link()
        self.program.bind()
 
        vertPositions = np.array([
            -0.5, -0.5,
            0.5, -0.5,
            -0.5, 0.5,
            0.5, 0.5], dtype=np.float32)
        self.vertPosBuffer = QOpenGLBuffer()
        self.vertPosBuffer.create()
        self.vertPosBuffer.bind()
        self.vertPosBuffer.allocate(vertPositions, len(vertPositions) * 4)
        self.program.setAttributeBuffer("aPosition", GL_FLOAT, 0, 2)
        self.program.enableAttributeArray("aPosition")
 
        self.uMvpMatrixLocation = self.program.uniformLocation("uMvpMatrix")
 
        self.viewMatrix = QMatrix4x4()
        self.viewMatrix.lookAt(QVector3D(0, 0, 1), QVector3D(0, 0, 0),
            QVector3D(0, 1, 0))
 
        self.projMatrix = QMatrix4x4()
        self.projViewMatrix = QMatrix4x4()
        self.modelMatrix = QMatrix4x4()
        self.mvpMatrix = QMatrix4x4()
 
    def resizeGL(self, w, h):
        coofWidth = w / self.initialWindowWidth
        coofHeight = h / self.initialWindowHeight
 
        self.projMatrix.setToIdentity()
        self.projMatrix.ortho(0, self.worldWidth * coofWidth,
            0, self.worldHeight * coofHeight, 1, -1)
        self.projViewMatrix = self.projMatrix * self.viewMatrix
 
    def paintGL(self):
        glClear(GL_COLOR_BUFFER_BIT)
        self.modelMatrix.setToIdentity()
        self.modelMatrix.translate(QVector3D(50, 50, 0))
        self.modelMatrix.rotate(10, QVector3D(0, 0, 1))
        self.modelMatrix.scale(QVector3D(80, 10, 1))
        self.mvpMatrix = self.projViewMatrix * self.modelMatrix
        self.program.setUniformValue(self.uMvpMatrixLocation, self.mvpMatrix)
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)
 
if __name__ == "__main__":
    QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL)
    app = QApplication(sys.argv)
    w = OpenGLWidget()
    w.show()
    sys.exit(app.exec())


Qt6 C++

main.cpp

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
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
#include <QtGui/QMatrix4x4>
#include <QtGui/QOpenGLFunctions>
#include <QtGui/QSurfaceFormat>
#include <QtGui/QVector3D>
#include <QtOpenGL/QOpenGLBuffer>
#include <QtOpenGL/QOpenGLShader>
#include <QtOpenGL/QOpenGLShaderProgram>
#include <QtOpenGLWidgets/QOpenGLWidget>
#include <QtWidgets/QApplication>
 
class OpenGLWidget : public QOpenGLWidget, private QOpenGLFunctions
{
 
public:
 
    OpenGLWidget()
    {
        setWindowTitle("OpenGL ES 2.0, Qt6, C++");
        resize(380, 380);
 
        QSurfaceFormat surfaceFormat;
        surfaceFormat.setDepthBufferSize(24);
        surfaceFormat.setSamples(4);
        setFormat(surfaceFormat);
    }
 
    void initializeGL() override
    {
        initializeOpenGLFunctions();
        glClearColor(0.188f, 0.22f, 0.255f, 1.f);
 
        QString vertShaderSrc =
            "attribute vec2 aPosition;\n"
            "uniform mat4 uMvpMatrix;"
            "void main()\n"
            "{\n"
            "    gl_Position = uMvpMatrix * vec4(aPosition, 0.0, 1.0);\n"
            "}\n";
 
        QString fragShaderSrc =
            "#ifdef GL_ES\n"
            "precision mediump float;\n"
            "#endif\n"
            "void main()\n"
            "{\n"
            "    gl_FragColor = vec4(0.2, 0.7, 0.3, 1.0);\n"
            "}\n";
 
        m_program.create();
        m_program.addShaderFromSourceCode(QOpenGLShader::ShaderTypeBit::Vertex, vertShaderSrc);
        m_program.addShaderFromSourceCode(QOpenGLShader::ShaderTypeBit::Fragment, fragShaderSrc);
        m_program.link();
        m_program.bind();
 
        float vertPositions[] = {
            -0.5f, -0.5f,
            0.5f, -0.5f,
            -0.5f, 0.5f,
            0.5f, 0.5f
        };
        m_vertPosBuffer.create();
        m_vertPosBuffer.bind();
        m_vertPosBuffer.allocate(vertPositions, sizeof(vertPositions));
        m_program.setAttributeBuffer("aPosition", GL_FLOAT, 0, 2);
        m_program.enableAttributeArray("aPosition");
 
        m_uMvpMatrixLocation = m_program.uniformLocation("uMvpMatrix");
        m_viewMatrix.lookAt(QVector3D(0, 0, 1), QVector3D(0, 0, 0), QVector3D(0, 1, 0));
    }
 
    void resizeGL(int w, int h) override
    {
        const float coofWidth = w / (float)m_initialWindowWidth;
        const float coofHeight = h / (float)m_initialWindowHeight;
 
        m_projMatrix.setToIdentity();
        m_projMatrix.ortho(0.f, m_worldWidth * coofWidth,
            0.f, m_worldHeight * coofHeight, 1.f, -1.f);
        m_projViewMatrix = m_projMatrix * m_viewMatrix;
    }
 
    void paintGL() override
    {
        glClear(GL_COLOR_BUFFER_BIT);
        m_modelMatrix.setToIdentity();
        m_modelMatrix.translate(QVector3D(50, 50, 0));
        m_modelMatrix.rotate(10, QVector3D(0, 0, 1));
        m_modelMatrix.scale(QVector3D(80, 10, 1));
        m_mvpMatrix = m_projViewMatrix * m_modelMatrix;
        m_program.setUniformValue(m_uMvpMatrixLocation, m_mvpMatrix);
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    }
 
private:
 
    QOpenGLBuffer m_vertPosBuffer;
    QOpenGLShaderProgram m_program;
    int m_uMvpMatrixLocation;
    QMatrix4x4 m_mvpMatrix;
    QMatrix4x4 m_projMatrix;
    QMatrix4x4 m_viewMatrix;
    QMatrix4x4 m_projViewMatrix;
    QMatrix4x4 m_modelMatrix;
    const int m_initialWindowWidth = 380;
    const int m_initialWindowHeight = 380;
    const float m_worldWidth = 100.f;
    const float m_worldHeight = 100.f;
};
 
int main(int argc, char *argv[])
{
    QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL);
    QApplication app(argc, argv);
    OpenGLWidget w;
    w.show();
    return app.exec();
}
transformed-rectangle-qopenglwidget.pro

Code
1
2
3
4
5
6
7
8
QT += core gui openglwidgets
 
win32: LIBS += -lopengl32
 
CONFIG += c++17
 
SOURCES += \
    main.cpp



Использование QOpenGLWindow для окна


PyQt6

main.py

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
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
import sys
 
import numpy as np
from OpenGL.GL import (GL_COLOR_BUFFER_BIT, GL_FLOAT, GL_TRIANGLE_STRIP,
                       glClear, glClearColor, glDrawArrays)
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QMatrix4x4, QSurfaceFormat, QVector3D
from PyQt6.QtOpenGL import (QOpenGLBuffer, QOpenGLShader, QOpenGLShaderProgram,
                            QOpenGLWindow)
from PyQt6.QtWidgets import QApplication
 
 
class OpenGLWindow(QOpenGLWindow):
 
    def __init__(self):
        super().__init__()
 
        self.setTitle("OpenGL ES 2.0, PyQt6, Python")
        self.initialWindowWidth = 380
        self.initialWindowHeight = 380
        self.resize(self.initialWindowWidth, self.initialWindowHeight)
        self.worldWidth = 100
        self.worldHeight = 100
 
        surfaceFormat = QSurfaceFormat()
        surfaceFormat.setDepthBufferSize(24)
        surfaceFormat.setSamples(4)
        self.setFormat(surfaceFormat)
 
    def initializeGL(self):
        glClearColor(0.188, 0.22, 0.255, 1)
 
        vertShaderSrc = """
            attribute vec2 aPosition;
            uniform mat4 uMvpMatrix;
            void main()
            {
                gl_Position = uMvpMatrix * vec4(aPosition, 0.0, 1.0);
            }
        """
 
        fragShaderSrc = """
            #ifdef GL_ES
            precision mediump float;
            #endif
            void main()
            {
                gl_FragColor = vec4(0.2, 0.7, 0.3, 1.0);
            }
        """
 
        self.program = QOpenGLShaderProgram()
        self.program.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Vertex, vertShaderSrc)
        self.program.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Fragment, fragShaderSrc)
        self.program.link()
        self.program.bind()
 
        vertPositions = np.array([
            -0.5, -0.5,
            0.5, -0.5,
            -0.5, 0.5,
            0.5, 0.5], dtype=np.float32)
        self.vertPosBuffer = QOpenGLBuffer()
        self.vertPosBuffer.create()
        self.vertPosBuffer.bind()
        self.vertPosBuffer.allocate(vertPositions, len(vertPositions) * 4)
        self.program.setAttributeBuffer("aPosition", GL_FLOAT, 0, 2)
        self.program.enableAttributeArray("aPosition")
 
        self.uMvpMatrixLocation = self.program.uniformLocation("uMvpMatrix")
 
        self.viewMatrix = QMatrix4x4()
        self.viewMatrix.lookAt(QVector3D(0, 0, 1), QVector3D(0, 0, 0),
            QVector3D(0, 1, 0))
 
        self.projMatrix = QMatrix4x4()
        self.projViewMatrix = QMatrix4x4()
        self.modelMatrix = QMatrix4x4()
        self.mvpMatrix = QMatrix4x4()
 
    def resizeGL(self, w, h):
        coofWidth = w / self.initialWindowWidth
        coofHeight = h / self.initialWindowHeight
 
        self.projMatrix.setToIdentity()
        self.projMatrix.ortho(0, self.worldWidth * coofWidth,
            0, self.worldHeight * coofHeight, 1, -1)
        self.projViewMatrix = self.projMatrix * self.viewMatrix
 
    def paintGL(self):
        glClear(GL_COLOR_BUFFER_BIT)
        self.modelMatrix.setToIdentity()
        self.modelMatrix.translate(QVector3D(50, 50, 0))
        self.modelMatrix.rotate(10, QVector3D(0, 0, 1))
        self.modelMatrix.scale(QVector3D(80, 10, 1))
        self.mvpMatrix = self.projViewMatrix * self.modelMatrix
        self.program.setUniformValue(self.uMvpMatrixLocation, self.mvpMatrix)
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)
 
if __name__ == "__main__":
    QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL)
    app = QApplication(sys.argv)
    w = OpenGLWindow()
    w.show()
    sys.exit(app.exec())


PySide6

main.py

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
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
import sys
 
import numpy as np
from OpenGL.GL import (GL_COLOR_BUFFER_BIT, GL_FLOAT, GL_TRIANGLE_STRIP,
                       glClear, glClearColor, glDrawArrays)
from PySide6.QtCore import Qt
from PySide6.QtGui import QMatrix4x4, QSurfaceFormat, QVector3D
from PySide6.QtOpenGL import (QOpenGLBuffer, QOpenGLShader,
                              QOpenGLShaderProgram, QOpenGLWindow)
from PySide6.QtWidgets import QApplication
 
 
class OpenGLWindow(QOpenGLWindow):
 
    def __init__(self):
        super().__init__()
 
        self.setTitle("OpenGL ES 2.0, PySide6, Python")
        self.initialWindowWidth = 380
        self.initialWindowHeight = 380
        self.resize(self.initialWindowWidth, self.initialWindowHeight)
        self.worldWidth = 100
        self.worldHeight = 100
 
        surfaceFormat = QSurfaceFormat()
        surfaceFormat.setDepthBufferSize(24)
        surfaceFormat.setSamples(4)
        self.setFormat(surfaceFormat)
 
    def initializeGL(self):
        glClearColor(0.188, 0.22, 0.255, 1)
 
        vertShaderSrc = """
            attribute vec2 aPosition;
            uniform mat4 uMvpMatrix;
            void main()
            {
                gl_Position = uMvpMatrix * vec4(aPosition, 0.0, 1.0);
            }
        """
 
        fragShaderSrc = """
            #ifdef GL_ES
            precision mediump float;
            #endif
            void main()
            {
                gl_FragColor = vec4(0.2, 0.7, 0.3, 1.0);
            }
        """
 
        self.program = QOpenGLShaderProgram()
        self.program.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Vertex, vertShaderSrc)
        self.program.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Fragment, fragShaderSrc)
        self.program.link()
        self.program.bind()
 
        vertPositions = np.array([
            -0.5, -0.5,
            0.5, -0.5,
            -0.5, 0.5,
            0.5, 0.5], dtype=np.float32)
        self.vertPosBuffer = QOpenGLBuffer()
        self.vertPosBuffer.create()
        self.vertPosBuffer.bind()
        self.vertPosBuffer.allocate(vertPositions, len(vertPositions) * 4)
        self.program.setAttributeBuffer("aPosition", GL_FLOAT, 0, 2)
        self.program.enableAttributeArray("aPosition")
 
        self.uMvpMatrixLocation = self.program.uniformLocation("uMvpMatrix")
 
        self.viewMatrix = QMatrix4x4()
        self.viewMatrix.lookAt(QVector3D(0, 0, 1), QVector3D(0, 0, 0),
            QVector3D(0, 1, 0))
 
        self.projMatrix = QMatrix4x4()
        self.projViewMatrix = QMatrix4x4()
        self.modelMatrix = QMatrix4x4()
        self.mvpMatrix = QMatrix4x4()
 
    def resizeGL(self, w, h):
        coofWidth = w / self.initialWindowWidth
        coofHeight = h / self.initialWindowHeight
 
        self.projMatrix.setToIdentity()
        self.projMatrix.ortho(0, self.worldWidth * coofWidth,
            0, self.worldHeight * coofHeight, 1, -1)
        self.projViewMatrix = self.projMatrix * self.viewMatrix
 
    def paintGL(self):
        glClear(GL_COLOR_BUFFER_BIT)
        self.modelMatrix.setToIdentity()
        self.modelMatrix.translate(QVector3D(50, 50, 0))
        self.modelMatrix.rotate(10, QVector3D(0, 0, 1))
        self.modelMatrix.scale(QVector3D(80, 10, 1))
        self.mvpMatrix = self.projViewMatrix * self.modelMatrix
        self.program.setUniformValue(self.uMvpMatrixLocation, self.mvpMatrix)
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)
 
if __name__ == "__main__":
    QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL)
    app = QApplication(sys.argv)
    w = OpenGLWindow()
    w.show()
    sys.exit(app.exec())


Qt6 C++

main.cpp

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
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
#include <QtGui/QMatrix4x4>
#include <QtGui/QOpenGLFunctions>
#include <QtGui/QSurfaceFormat>
#include <QtGui/QVector3D>
#include <QtOpenGL/QOpenGLBuffer>
#include <QtOpenGL/QOpenGLShader>
#include <QtOpenGL/QOpenGLShaderProgram>
#include <QtOpenGL/QOpenGLWindow>
#include <QtWidgets/QApplication>
 
class OpenGLWindow : public QOpenGLWindow, private QOpenGLFunctions
{
 
public:
 
    OpenGLWindow()
    {
        setTitle("OpenGL ES 2.0, Qt6, C++");
        resize(380, 380);
 
        QSurfaceFormat surfaceFormat;
        surfaceFormat.setDepthBufferSize(24);
        surfaceFormat.setSamples(4);
        setFormat(surfaceFormat);
    }
 
    void initializeGL() override
    {
        initializeOpenGLFunctions();
        glClearColor(0.188f, 0.22f, 0.255f, 1.f);
 
        QString vertShaderSrc =
            "attribute vec2 aPosition;\n"
            "uniform mat4 uMvpMatrix;"
            "void main()\n"
            "{\n"
            "    gl_Position = uMvpMatrix * vec4(aPosition, 0.0, 1.0);\n"
            "}\n";
 
        QString fragShaderSrc =
            "#ifdef GL_ES\n"
            "precision mediump float;\n"
            "#endif\n"
            "void main()\n"
            "{\n"
            "    gl_FragColor = vec4(0.2, 0.7, 0.3, 1.0);\n"
            "}\n";
 
        m_program.create();
        m_program.addShaderFromSourceCode(QOpenGLShader::ShaderTypeBit::Vertex, vertShaderSrc);
        m_program.addShaderFromSourceCode(QOpenGLShader::ShaderTypeBit::Fragment, fragShaderSrc);
        m_program.link();
        m_program.bind();
 
        float vertPositions[] = {
            -0.5f, -0.5f,
            0.5f, -0.5f,
            -0.5f, 0.5f,
            0.5f, 0.5f
        };
        m_vertPosBuffer.create();
        m_vertPosBuffer.bind();
        m_vertPosBuffer.allocate(vertPositions, sizeof(vertPositions));
        m_program.setAttributeBuffer("aPosition", GL_FLOAT, 0, 2);
        m_program.enableAttributeArray("aPosition");
 
        m_uMvpMatrixLocation = m_program.uniformLocation("uMvpMatrix");
        m_viewMatrix.lookAt(QVector3D(0, 0, 1), QVector3D(0, 0, 0), QVector3D(0, 1, 0));
    }
 
    void resizeGL(int w, int h) override
    {
        const float coofWidth = w / (float)m_initialWindowWidth;
        const float coofHeight = h / (float)m_initialWindowHeight;
 
        m_projMatrix.setToIdentity();
        m_projMatrix.ortho(0.f, m_worldWidth * coofWidth,
            0.f, m_worldHeight * coofHeight, 1.f, -1.f);
        m_projViewMatrix = m_projMatrix * m_viewMatrix;
    }
 
    void paintGL() override
    {
        glClear(GL_COLOR_BUFFER_BIT);
        m_modelMatrix.setToIdentity();
        m_modelMatrix.translate(QVector3D(50, 50, 0));
        m_modelMatrix.rotate(10, QVector3D(0, 0, 1));
        m_modelMatrix.scale(QVector3D(80, 10, 1));
        m_mvpMatrix = m_projViewMatrix * m_modelMatrix;
        m_program.setUniformValue(m_uMvpMatrixLocation, m_mvpMatrix);
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    }
 
private:
 
    QOpenGLBuffer m_vertPosBuffer;
    QOpenGLShaderProgram m_program;
    int m_uMvpMatrixLocation;
    QMatrix4x4 m_mvpMatrix;
    QMatrix4x4 m_projMatrix;
    QMatrix4x4 m_viewMatrix;
    QMatrix4x4 m_projViewMatrix;
    QMatrix4x4 m_modelMatrix;
    const int m_initialWindowWidth = 380;
    const int m_initialWindowHeight = 380;
    const float m_worldWidth = 100.f;
    const float m_worldHeight = 100.f;
};
 
int main(int argc, char *argv[])
{
    QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL);
    QApplication app(argc, argv);
    OpenGLWindow w;
    w.show();
    return app.exec();
}
transformed-rectangle-qopenglwindow.pro

Code
1
2
3
4
5
6
7
8
QT += core gui openglwidgets
 
win32: LIBS += -lopengl32
 
CONFIG += c++17
 
SOURCES += \
    main.cpp






Миниатюры
0
9945 / 2946 / 496
Регистрация: 05.10.2013
Сообщений: 8,016
Записей в блоге: 241
25.06.2024, 14:21
Цитата Сообщение от 8Observer8 Посмотреть сообщение
чтобы создать EXE
Дело в том, что если собрать веб-приложение в исполняемое приложение с EXE с помощью Electron, то оно будет весить примерно 200-300 MB (точно не помню), а на Qt C++ исполняемое приложение с EXE будет весить примерно в 10 раз меньше. На Python можно не собирать EXE и тогда вес desktop-приложения будет равен весу исходников и ассетов. Правда, если собирать Python приложение в исполняемое приложение с EXE с помощью PyInstaller, то оно тоже будет весить много - 100-200 МБ. На C++, возможно, в некоторых ситуациях, приложение будет работать в разы и даже на порядки быстрее.
0
9945 / 2946 / 496
Регистрация: 05.10.2013
Сообщений: 8,016
Записей в блоге: 241
26.06.2024, 01:58
Шейдерная программа

shader-program.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
43
import { gl } from "./webgl-context.js";
 
export default async function createProgram(path, vertShaderFileName,
    fragShaderFileName) //
{
    let response = await fetch(path + vertShaderFileName);
    const vertShaderSource = await response.text();
    response = await fetch(path + fragShaderFileName);
    const fragShaderSource = await response.text();
 
    const vShader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vShader, vertShaderSource);
    gl.compileShader(vShader);
    let ok = gl.getShaderParameter(vShader, gl.COMPILE_STATUS);
    if (!ok) {
        console.log(`${vertShaderFileName}: ${gl.getShaderInfoLog(vShader)}`);
        return null;
    };
 
    const fShader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fShader, fragShaderSource);
    gl.compileShader(fShader);
    ok = gl.getShaderParameter(fShader, gl.COMPILE_STATUS);
    if (!ok) {
        console.log(`${fragShaderFileName}: ${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 error with shaders ${vertShaderFileName}` +
            ` and ${fragShaderFileName}`);
        console.log(gl.getProgramInfoLog(program));
        return null;
    };
    gl.useProgram(program);
 
    return program;
}


Шейдерная программа - это объект через который происходит общение с вершинным и фрагментным шейдерами, то есть пересылка данных, например, передача MVP-матрицы. В файле shader-program.js происходит передача исходников шейдеров на видеокарту. Отдаётся команда на компиляцию и линковку шейдеров. В конечном итоге возвращается объект шейдерной программы.
0
403 / 19 / 5
Регистрация: 17.01.2017
Сообщений: 572
09.11.2024, 10:57  [ТС]
Лучший ответ Сообщение было отмечено 8Observer8 как решение

Решение

8Observer8, решила ещё раз поискать функцию drawTriangle(flash), только на html5. На этот раз поиски увенчались успехом. Мне удалось найти не только эту функцию на и целую библиотеку. Называется она IvankLib. Там есть почти все функции Flash, только нет startDrag и stopDrag, но это не особо важно можно захват объекта сделать другими способами.
Например.
https://lib.ivank.net/?p=demos&d=mevents
Для сравнения два примера.
На flash.
ActionScript 3
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
package
{
 import flash.display.Sprite;
 import flash.display.BitmapData;
 import flash.display.Bitmap;
 import flash.display.*
 import flash.events.*
 public class Main extends Sprite
 {
 var archer1:BitmapData = new archer(0, 0);
 
  private var bitmap:Bitmap = new Bitmap(archer1);
  private var _circkHolder:Sprite  
  
  private var vert:Vector.<Number> = new Vector.<Number>()
  private var vert2:Vector.<Number> = new Vector.<Number>()
  private var uvt:Vector.<Number> = new Vector.<Number>()
  private var ind:Vector.<int> = new Vector.<int>()
   var v:Vector.<int>
  private var res:Number = 100
  private var cols:int = 5
  private var rows:int = 4
 
 
 public function Main():void
 {
    
    _circkHolder = new Sprite()
   addChild(_circkHolder)
    
    
    makeTriangls()
   makePoints()
    graphics.beginBitmapFill(bitmap.bitmapData);
    
    
    
    graphics.drawTriangles(vert, ind, uvt)
    graphics.endFill()
    
    graphics.lineStyle(0)
    graphics.drawTriangles(vert, ind)
    
    
 }
 private function makeTriangls():void {
 
 
    vert = Vector.<Number>([100,100,200,100,300,100,400,100,500,100,100,200,200,200,300,200,400,200,500,200,100,300,200,300,300,300,400,300,500,300,100,400,200,400,300,400,400,400,500,400]);
    trace(vert.length);
    
    uvt = Vector.<Number>([0,0,0.25,0,0.5,0,0.75,0,1,0,0,0.3333333333333333,0.25,0.3333333333333333,0.5,0.3333333333333333,0.75,0.3333333333333333,1,0.3333333333333333,0,0.6666666666666666,0.25,0.6666666666666666,0.5,0.6666666666666666,0.75,0.6666666666666666,1,0.6666666666666666,0,1,0.25,1,0.5,1,0.75,1,1,1]);
    trace(uvt.length);
    ind = Vector.<int>([0,1,5,1,6,5,1,2,6,2,7,6,2,3,7,3,8,7,3,4,8,4,9,8,5,6,10,6,11,10,6,7,11,7,12,11,7,8,12,8,13,12,8,9,13,9,14,13,10,11,15,11,16,15,11,12,16,12,17,16,12,13,17,13,18,17,13,14,18,14,19,18
]);
    
  }
  private function makePoints():void {
    var mc:Sprite
    for (var i:int = 0; i < vert.length; i += 2 ) {    
    mc = makePoint()
    mc.x = vert[i];
    mc.y = vert[i + 1];
    mc.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown1)
    }
  }
  private function makePoint():Sprite {
    var mc:Sprite = new Sprite()
    mc.graphics.beginFill(0x000000)
    mc.graphics.drawCircle( 0, 0, 5)
    mc.graphics.endFill()
    _circkHolder.addChild(mc)
    return mc
  }
   private function onMouseDown1(e:MouseEvent):void {
   e.target.startDrag()
   stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove1)
   stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp1)
    }
 private function onMouseMove1(e:MouseEvent):void {
    draw1()
  }
  private function onMouseUp1(e:MouseEvent):void {
    e.target.stopDrag()
    stage.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown1)
    stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp1)
  }
   private function draw1():void {
    var n:int = 0
    var mc:Sprite
    for (var i:int = 0; i < vert.length; i += 2 ) {
     mc = _circkHolder.getChildAt(n) as Sprite
    // trace("mc = _circkHolder.getChildAt("+n+") as Sprite");
    // trace("vert["+i+"] = mc.x");
     //trace("vert["+i+" + 1] = mc.y");
     vert[i] = mc.x
     vert[i + 1] = mc.y
     n++
    }
    graphics.clear()
 
    graphics.beginBitmapFill(bitmap.bitmapData)
    graphics.drawTriangles(vert, ind, uvt)
    graphics.endFill()
  }
 }
 
}
А вот написала, тот же пример на html5.
HTML5
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
<html>
<head>
     <script type="text/javascript" src="./Utils.js"></script>
     <script type="text/javascript" src="./geom/geom.js"></script>
     <script type="text/javascript" src="./geom/Point.js"></script>
     <script type="text/javascript" src="./geom/Rectangle.js"></script>
     <script type="text/javascript" src="./geom/Transform.js"></script>
     <script type="text/javascript" src="./geom/Vector3D.js"></script>
     
     
     
     <script type="text/javascript" src="./events/Event.js"></script>
     <script type="text/javascript" src="./events/EventDispatcher.js"></script>
     <script type="text/javascript" src="./events/events.js"></script>
     <script type="text/javascript" src="./events/KeyboardEvent.js"></script>
     <script type="text/javascript" src="./events/MouseEvent.js"></script>
     <script type="text/javascript" src="./events/TouchEvent.js"></script>
     <script type="text/javascript" src="./display/BlendMode.js"></script>
     <script type="text/javascript" src="./display/DisplayObject.js"></script>
     <script type="text/javascript" src="./display/InteractiveObject.js"></script>
     <script type="text/javascript" src="./text/text.js"></script>
     <script type="text/javascript" src="./text/TextField.js"></script>
     <script type="text/javascript" src="./text/TextFormat.js"></script>
     <script type="text/javascript" src="./text/TextFormatAlign.js"></script>
     
     
     
     <script type="text/javascript" src="./display/Bitmap.js"></script>
     <script type="text/javascript" src="./display/BitmapData.js"></script>
     
     <script type="text/javascript" src="./display/display.js"></script>
     
     <script type="text/javascript" src="./display/DisplayObjectContainer.js"></script>
     <script type="text/javascript" src="./display/Graphics.js"></script>
     
     <script type="text/javascript" src="./display/Sprite.js"></script>
     <script type="text/javascript" src="./display/Stage.js"></script>
     
     <script type="text/javascript">
          function Start()
         {
               var stage = new Stage("c");
               var s = new Sprite();
               imgData    = new BitmapData("archer.jpg");
               
               var _circkHolder = new Sprite()
                var p = new Point(0,0), cur = null;
               stage.addChild(s);
               stage.addChild(_circkHolder)
               
              var vertices, indices, uvtData;
               
               
               var mc;
               makeTriangls();
               makePoints();
               
                function makeTriangls() {
 
                 
                    vertices = [100,100,200,100,300,100,400,100,500,100,100,200,200,200,300,200,400,200,500,200,100,300,200,300,300,300,400,300,500,300,100,400,200,400,300,400,400,400,500,400];
               
                indices = [0,1,5,1,6,5,1,2,6,2,7,6,2,3,7,3,8,7,3,4,8,4,9,8,5,6,10,6,11,10,6,7,11,7,12,11,7,8,12,8,13,12,8,9,13,9,14,13,10,11,15,11,16,15,11,12,16,12,17,16,12,13,17,13,18,17,13,14,18,14,19,18
];
                
                
                uvtData = [0,0,0.2,0,0.5,0,0.7,0,1,0,0,0.3,0.2,0.3,0.5,0.3,0.7,0.3,1,0.3,0,0.6,0.2,0.6,0.5,0.6,0.7,0.6,1,0.6,0,1,0.2,1,0.5,1,0.7,1,1,1];
                  
                  }
                  function makePoints() {
                      for (var i = 0; i < vertices.length; i += 2 ) {  
                            mc = makePoint()
                            mc.x = vertices[i];
                            mc.y = vertices[i + 1];
                            mc.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown1)
                      }
                  }
                  //onMouseDown1
                  function onMouseDown1 (e)
                  { 
                    
                    cur = e.target; 
                    p.x = cur.mouseX; 
                    p.y = cur.mouseY;
                    stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove1)
                    stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp1)
                   
                  }
                  function onMouseMove1 (e)
                  { 
                     if(cur == null) return;
                    cur.x = stage.mouseX - p.x;
                    cur.y = stage.mouseY - p.y;
                    draw1();
                  }
                  function onMouseUp1 (e)
                  { 
                     cur = null;
                  }
                  
                   function draw1() {
                      var n = 0;
                      var mc;
                      for (var i = 0; i < vertices.length; i += 2 )                       {
                          
                          mc = _circkHolder.getChildAt(n);
                         
                          vertices[i] = mc.x
                          vertices[i + 1] = mc.y;
                    
                         n++
                      }
                       s.graphics.clear();
                       s.graphics.beginBitmapFill(imgData);
                     
                       s.graphics.drawTriangles(vertices, indices,uvtData);
                       s.graphics.endFill();
                   }
                  
                   function makePoint() {
                      var mc = new Sprite();
                      mc.graphics.beginFill(0x000000)
                      mc.graphics.drawCircle( 0, 0, 5)
                      mc.graphics.endFill()
                      _circkHolder.addChild(mc)
                      return mc
                  }
               
               
               s.graphics.clear();
               s.graphics.beginBitmapFill(imgData);
               
               s.graphics.drawTriangles(vertices, indices,uvtData);
               s.graphics.endFill();
          }
     </script>
</head>
<body onload="Start();"><canvas id="c"></canvas></body>
</html>
Flash код и html5 код почти идентичны. Разумеется код не идеальный, потом перепишу.
Вот архив с работающим примером где изображение можно растягивать передвигая точки.
drawTrinagle.zip
1
403 / 19 / 5
Регистрация: 17.01.2017
Сообщений: 572
12.11.2024, 08:49  [ТС]
8Observer8, вот пример без использовании библиотек, правда не похож вариант на flash, пыталась перенести координаты вершин с flash. Здесь получилось по другому и вершины на flash не работают.
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
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>drawTriangles</title>
 
<script>
var canvas, ctx, img;
var num = 2;
var vertices;
var indices;
var uvtData;
var width = 200;
var height = 150;
var xPos = 200;
var yPos = 150;
var dragok = false;
window.onload = function()
{
 var i,j,obj;
    vertices = new Array();
    for(i=0;i<=num;i++){
        for(j=0;j<=num;j++){
            vertices.push(i*width,j*height);
        }
    }
    indices = new Array();
    for(i=0;i<num;i++){
        for(j=0;j<num;j++){
            indices.push(i*(num+1)+j,(i+1)*(num+1)+j,i*(num+1)+j+1);
            indices.push((i+1)*(num+1)+j,i*(num+1)+j+1,(i+1)*(num+1)+j+1);
        }
    }
    uvtData = new Array();
    for(i=0;i<=num;i++){
        for(j=0;j<=num;j++){
            uvtData.push(i/num, j/num);
        }
    }
canvas = document.getElementById("drawingCanvas");
ctx = canvas.getContext("2d");
var BB=canvas.getBoundingClientRect();
var offsetX=BB.left;
var offsetY=BB.top;
 
canvas.onmousedown = down;
canvas.onmouseup = up;
canvas.onmousemove = move;
 
pointList = new Array();
for(i = 0;i < vertices.length;i+=2){
  var obj = {x:vertices[i], y:vertices[i+1],isDragging:false};
    pointList.push(obj);
}
 
 
var img = new Image();
 
img.src = "archer.jpg";
setTimeout(draw1,1000);
var c = ctx;
function draw1()
{
    setInterval(() => {
    (
                    function() {
                        ctx.clearRect(0, 0, canvas.width, canvas.height);
                        ctx.save(); 
                        ctx.translate(xPos, yPos);
                        drawTriangles(vertices, indices, uvtData);
                        ctx.restore(); 
                        draw();
                        
                        points = pointList.map(p => [p.x,p.y]).flat();
                     
                        for(var i = 0; i < vertices.length;i++)
                        {
                            vertices[i] = points[i];
                        }
                        
                        
                    }).call(this);
    }, 33);
     
}
 
 function down(event){
   
      event.preventDefault();
      event.stopPropagation();
      mouseX = event.offsetX - xPos;
      mouseY = event.offsetY - yPos;
      
       var mx=parseInt(event.clientX-offsetX);
       var my=parseInt(event.clientY-offsetY);
       
       dragok=false;
       var i,obj;
        for(i = 0;i < pointList.length;i++){
          obj = pointList[i];
         
          if(Math.pow(obj.x-mouseX,2)+Math.pow(obj.y-mouseY,2) < Math.pow(20,2)){
            dragok=true;
            obj.isDragging=true;
          }
        }
        startX=mx;
        startY=my;
    }
    function up(event){
        event.preventDefault();
        event.stopPropagation();
 
        dragok = false;
        for(var i=0;i<pointList.length;i++){
          pointList[i].isDragging=false;
        }
   }
    function move(event){
      if (dragok){
          event.preventDefault();
          event.stopPropagation();
 
          
          var mx=parseInt(event.clientX-offsetX);
          var my=parseInt(event.clientY-offsetY);
 
          
          var dx=mx-startX;
          var dy=my-startY;
 
          
          for(var i=0;i<pointList.length;i++){
            var obj=pointList[i];
            
             
            
            
            if(obj.isDragging){
              obj.x+=dx;
              obj.y+=dy;
            }
          }
          
          startX=mx;
          startY=my;
 
        }
   }
 
function draw()
{     
     var jj = 0;
      for(i = 0;i < vertices.length;i+=2){
          c.save();
          c.translate(pointList[jj].x+xPos, pointList[jj].y+yPos);
          c.beginPath();
          c.arc(0, 0, 10, 0, 2*Math.PI, undefined);
          c.fillStyle = "#ff0000";
          c.fill();
          c.lineWidth = 1;
          c.strokeStyle = "#ff0000";
          c.stroke();
          c.restore();
          jj++;
          
      }
}
 
function drawTriangles(ve, ind, u, tn, lco)
{ 
    var i, j, l = ind.length, c;
    var v = ve, a, k, sw;
    c = ctx;
    
    for (i = 0, j = 0; i < l; i += 3) {
          a = 0;
                    c.save();
                    c.beginPath();
                    c.moveTo(v[ind[i] * 2], v[ind[i] * 2 + 1]);
                    c.lineTo(v[ind[i + 1] * 2], v[ind[i + 1] * 2 + 1]);
                    c.lineTo(v[ind[i + 2] * 2], v[ind[i + 2] * 2 + 1]);
                    c.lineTo(v[ind[i] * 2], v[ind[i] * 2 + 1]);
                    c.closePath();
                    c.clip();
                    if (i % 6 == 0) {
              sw = -1;
              var w = (u[ind[i + 1 + j] * 2] - u[ind[i + j] * 2]) * img.width;
              var h = (u[ind[i + 2] * 2 + 1] - u[ind[i] * 2 + 1]) * img.height;
              if (j == 0 && w < 0) {
                  for (k = i + 9; k < l; k += 3) {
                    if (u[ind[i + 2] * 2 + 1] == u[ind[k + 2] * 2 + 1]) {
                      j = k - i;
                      break;
                    }
                  }
                  if (j == 0) {
                    j = l - i;
                  }
                  w = (u[ind[i + 1 + j] * 2] - u[ind[i + j] * 2]) * img.width;
                }
                if (i + j >= l) {
                  w = (u[ind[i + j - l] * 2] - u[ind[i + 1] * 2]) * img.width;
                  sw = u[ind[i] * 2] == 1 ? 0 : img.width * u[ind[i] * 2] + w;
                  if (sw > img.width) {
                    sw -= img.width;
                  }
                } else {
                  sw = img.width * u[ind[i + j] * 2];
                }
                sh = img.height * u[ind[i] * 2 + 1];
                if (h < 0) {
                  h = (u[ind[i + 2 - (i > 0 ? 6 : -6)] * 2 + 1] - u[ind[i - (i > 0 ? 6 : -6)] * 2 + 1]) * img.height;
                  sh = 0;
                }
                var t1 = (v[ind[i + 1] * 2] - v[ind[i] * 2]) / w;
                var t2 = (v[ind[i + 1] * 2 + 1] - v[ind[i] * 2 + 1]) / w;
                var t3 = (v[ind[i + 2] * 2] - v[ind[i] * 2]) / h;
                var t4 = (v[ind[i + 2] * 2 + 1] - v[ind[i] * 2 + 1]) / h;
                c.transform(t1, t2, t3, t4, v[ind[i] * 2], v[ind[i] * 2 + 1]);
                
                c.drawImage(img,
                                    img.x + sw,
                                    img.y + sh,
                                    w, h,
                                    0, 0,
                                    w, h);
                    } 
                    else
                    {
              var w = (u[ind[i + 2 + j] * 2] - u[ind[i + 1 + j] * 2]) * img.width;
              var h = (u[ind[i + 2] * 2 + 1] - u[ind[i] * 2 + 1]) * img.height;
              if (j == 0 && w < 0) {
                            for (k = i + 9; k < l; k += 3) {
                                if (u[ind[i + 2] * 2 + 1] == u[ind[k + 2] * 2 + 1]) {
                                    j = k - i;
                                    break;
                                }
                            }
                            if (j == 0) {
                                j = l - i;
                            }
                            w = (u[ind[i + 2 + j] * 2] - u[ind[i + 1 + j] * 2]) * img.width;
                        }
                        if (i + 1 + j >= l) {
                            w = (u[ind[i + 1 + j - l] * 2] - u[ind[i + 2] * 2]) * img.width;
                            sw = u[ind[i + 1] * 2] == 1 ? 0 : img.width * u[ind[i + 1] * 2] + w;
                            if (sw > img.width) {
                                sw -= img.width;
                            }
                        } else {
                            sw = img.width * u[ind[i + 1 + j] * 2];
                        }
                        sh = img.height * u[ind[i] * 2 + 1];
                        if (h < 0) {
                            h = (u[ind[i + 2 - (i > 0 ? 6 : -6)] * 2 + 1] - u[ind[i - (i > 0 ? 6 : -6)] * 2 + 1]) * img.height;
                            sh = 0;
                        }
                        var t1 = (v[ind[i + 2] * 2] - v[ind[i + 1] * 2]) / w;
                        var t2 = (v[ind[i + 2] * 2 + 1] - v[ind[i + 1] * 2 + 1]) / w;
                        var t3 = (v[ind[i + 2] * 2] - v[ind[i] * 2]) / h;
                        var t4 = (v[ind[i + 2] * 2 + 1] - v[ind[i] * 2 + 1]) / h;
                        c.transform(t1, t2, t3, t4, v[ind[i + 1] * 2], v[ind[i + 1] * 2 + 1]);
                        
                        c.drawImage(img,
                                img.x + sw,
                                img.y + sh,
                                w, h,
                                0, -h,
                                w, h);
                    }
                    c.restore();
    }
}
}
 
</script>
</head>
<body>
<canvas id="drawingCanvas" style="background:#444444" width="800px" height="800px"></canvas><br>
</body>
</html>
Архив с кодом:
drawTriangleArcher.zip

Хватаем маркеры мышкой и перетаскиваем картинка расширяется.

Самая правильная библиотека которая копирует точную функции из flash, это "ivank". Про который я указала выше. Я протестировала более сложный пример где тоже используется drawTriangle и всё сработало. Удалось переделать код за пару часов . Так что для переноса своих сложных проектов с flash на html5 подойдёт.
1
383 / 23 / 2
Регистрация: 12.06.2021
Сообщений: 211
Записей в блоге: 2
29.05.2025, 15:01
Стало любопытно посмотреть, что за функция drawTriangles. Решила попробовать сделать тоже самое на Pixi. Работаю сейчас с этой библиотекой. Простой пример.
Main1.html

HTML5
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
<!DOCTYPE html>
<html lang="en" >
 
<head>
  <meta charset="UTF-8">
  <title>drawTriangles Mesh</title>
</head>
<body>
  
<!-- 
<script src='https://code.jquery.com/jquery-1.12.0.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.1.3/pixi.min.js'></script>
    -->
    <script src='libs/jquery-1.12.0.min.js'></script>
<script src='libs/pixi.min.js'></script>
      <script>
var Lrenderer = new PIXI.Renderer({
  width: 800,
  height: 600,
  backgroundColor: 0x000000 });
 
document.body.appendChild(Lrenderer.view);
 
 
const vertices = [0,0,0,120,0,240,129,0,129,120,129,240,258,0,258,120,258,240];
 
  const uvtData = [0,0,0,0.5,0,1,0.5,0,0.5,0.5,0.5,1,1,0,1,0.5,1,1];
 
  const indices = [0,3,1,3,1,4,1,4,2,4,2,5,3,6,4,6,4,7,4,7,5,7,5,8];
  const uvs = uvtData;
 
var Lstage = new PIXI.Container();
 
PIXI.Loader.shared.add("image", "archer.jpg").load((loader, resources) => {
     const texture = resources.image.texture;
    
     const mesh = new PIXI.SimpleMesh(
      texture,
      new Float32Array(vertices),
      new Float32Array(uvs),
      new Uint16Array(indices),
      PIXI.DRAW_MODES.TRIANGLES
    );
    
     mesh.position.set(0, 0);
     Lstage.addChild(mesh);
     
      // Create draggable vertex points
    const points = [];
    for (let i = 0; i < vertices.length; i += 2) {
      const circle = new PIXI.Graphics();
      circle.beginFill(0xff0000);
      circle.drawCircle(0, 0, 6);
      circle.endFill();
      circle.x = vertices[i];
      circle.y = vertices[i + 1];
      circle.interactive = true;
      circle.buttonMode = true;
      circle.vertexIndex = i;
      Lstage.addChild(circle);
      points.push(circle);
 
      circle
        .on("pointerdown", onDragStart)
        .on("pointerup", onDragEnd)
        .on("pointerupoutside", onDragEnd)
        .on("pointermove", onDragMove);
    }
    
    function onDragStart(event) {
      this.data = event.data;
      this.dragging = true;
    }
 
    function onDragEnd() {
      this.dragging = false;
      this.data = null;
    }
    
 
    function onDragMove() {
         if (this.dragging) {
             const newPosition = this.data.getLocalPosition(Lstage);
              this.x = newPosition.x;
              this.y = newPosition.y;
              // Update vertex position in mesh
              mesh.vertices[this.vertexIndex] = this.x;
              mesh.vertices[this.vertexIndex + 1] = this.y;
           
        }
    }
    
      animate();
      
      function animate() {
         
          Lrenderer.render(Lstage);
          requestAnimationFrame(animate);
        }
});
 
 </script>
 
  
</body>
 
</html>
Всё получилось, код работает?
Изменила данные и добавила из предыдущих постов (Примеры выше).
Code
1
2
3
4
5
6
const vertices = [100,100,200,100,300,100,400,100,500,100,100,200,200,200,300,200,400,200,500,200,100,300,200,300,300,300,400,300,500,300,100,400,200,400,300,400,400,400,500,400];
 
  const uvtData = [0,0,0.25,0,0.5,0,0.75,0,1,0,0,0.3333333333333333,0.25,0.3333333333333333,0.5,0.3333333333333333,0.75,0.3333333333333333,1,0.3333333333333333,0,0.6666666666666666,0.25,0.6666666666666666,0.5,0.6666666666666666,0.75,0.6666666666666666,1,0.6666666666666666,0,1,0.25,1,0.5,1,0.75,1,1,1];
 
  const indices = [0,1,5,1,6,5,1,2,6,2,7,6,2,3,7,3,8,7,3,4,8,4,9,8,5,6,10,6,11,10,6,7,11,7,12,11,7,8,12,8,13,12,8,9,13,9,14,13,10,11,15,11,16,15,11,12,16,12,17,16,12,13,17,13,18,17,13,14,18,14,19,18
];
Тоже всё заработало. Так что pixi вполне подходит для создания drawTriangles.

Полностью исходный код прикреплён.
drawTrianglesPixi.zip

Небольшая справка: PIXI - это библиотека javascript для работы с 2d-графикой. Не смотря, что основой является 2D, PIXI использует технологию WebGL. Так что для построения triangles у нас была также задействована технология WebGL.
0
9945 / 2946 / 496
Регистрация: 05.10.2013
Сообщений: 8,016
Записей в блоге: 241
29.05.2025, 17:15
У вас в архиве версия Pixi.js v5.1.3 от 2019-ого года:
JavaScript
1
2
3
4
5
/*!
 * pixi.js - v5.1.3
 * Compiled Mon, 09 Sep 2019 04:51:53 UTC
...
*/
Я пробовал версию 7.2.4. На данный момент крайняя версия 8.9.2, где произошли большие изменения по сравнению с версией v7, судя по руководству по миграции с v7 на v8: https://pixijs.com/8.x/guides/migrations/v8 Скорее всего, лучше использовать v8, так как, наверное, эту версию сейчас использует большинство и тогда будет проще получать ответы. Либо большинство все его на v7. Этот вопрос спорный, какую версию использовать. Может вы учите Pixi.js по книге, где v5, поэтому вам пока легче использовать эту версию. Может DeepSeek или ChatGPT лучше знает v5. Новые версии они могут знать плохо, но с другой стороны может 8.9.2 появилась достаточно давно.

Цитата Сообщение от Olga28 Посмотреть сообщение
Не смотря, что основой является 2D, PIXI использует технологию WebGL.
По умолчанию, да, Pixi.js перед запуском проверяет доступен ли графический API WebGL 2.0 в данном браузере. Если WebGL 2.0 недоступен, то происходит проверка на наличие WebGL 1.0. Если WebGL 1.0 недоступен, то используется Canvas API. Вполне возможно, что в будущих версиях будет поддержка WebGPU - это новый графический API для браузеров, скорее всего, похожий на Vulkan, так как WebGL 1.0 и OpenGL ES 2.0 один в один, а продолжением OpenGL стал Vulkan, поэтому логично предположить, что WebGPU будет очень похож на Vulkan, так как OpenGL, WebGL, Vulkan и WebGPU разработала один консорциум - Khronos Group. ChatGPT говорит, что WebGPU и Vulkan очень похожи, а дальше я проверять не стал. Сейчас WebGPU не поддерживается в Firefox: https://caniuse.com/webgpu То есть, когда WebGPU добавят в Pixi.js, а рано или поздно это должно произойти, то Pixi.js будет проверять сначала WebGPU и будет его использовать, если он доступен, а если WebGPU недоступен, то будет проверять WebGL 2.0, WebGL 1.0 и в конечно итоге - Canvas API: https://developer.mozilla.org/... Canvas_API
0
383 / 23 / 2
Регистрация: 12.06.2021
Сообщений: 211
Записей в блоге: 2
29.05.2025, 17:19
8Observer8,

Может вы учите Pixi.js по книге, где v5, поэтому вам пока легче использовать эту версию.
Я просто учу исходный коды по песочницам. База есть. Если попадутся новые функции можно посмотреть в интернете. По исходникам быстрее чем читать книги. Что касается Pixi.js эту библиотеку я стянула с codepen когда разбирала очередной код. Специально версию не выбирала да и за обновлением библиотек я не слежу.

Если WebGL 2.0 недоступен, то происходит проверка на наличие WebGL 1.0. Если WebGL 1.0 недоступен, то используется Canvas API.
А как сразу активировать Canvas API?
Хочу посмотреть как один и тот же код будет работать под разные API.
0
9945 / 2946 / 496
Регистрация: 05.10.2013
Сообщений: 8,016
Записей в блоге: 241
29.05.2025, 20:58
Цитата Сообщение от Olga28 Посмотреть сообщение
А как сразу активировать Canvas API?
Хочу посмотреть как один и тот же код будет работать под разные API.
Я нашёл информацию, что в конце 2022 года была проблема с активацией Canvas API, но её решили в версии v7.0.4: Missing view option to CanvasRenderer. Там есть ссылка на пример в песочнице: https://jsfiddle.net/bigtimebuddy/t1u9678x/

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//use pixi.js 7.0.4 and pixi-legacy.js 7.0.4
// cannot appear canvas if following option specified forceCanvas: true and specify view
const app = new PIXI.Application({
    view: document.querySelector("#cv"),
  forceCanvas:true 
});
 
//but, appear canvas if appendChild app.view after initialize application.
//document.body.appendChild(app.view);
 
// Draw a shape (for check display)
const shape = new PIXI.Graphics();
app.stage.addChild(shape);
 
shape
  .beginFill(0xff0000)
  .drawRect(0,0,100,100);
То есть для этого нужно использовать pixi-legacy.js и флаг forceCanvas. Не знаю как в v5, а в v7 получается убрали Canvas API в отдельный плагин и теперь всё рисуется с помощью WebGL, как вы писали. Выбор автоматически происходит только между версиями WebGL, то есть WebGL 1.0 или WebGL 2.0

Добавлено через 8 минут
По поводу поддержки Canvas API нашёл следующую информацию, когда вышла и обновлялась v5: autoDetectRenderer no longer in v5?

Перевод Google Translate ответа одного из разработчиков Pixi.js:

Короткий ответ: мы не удалили его, но вот некоторый контекст о v5:

Мы решили сделать context2d рендеринг второсортным в мире Pixi. В v4, WebGL и Canvas мы почти равны из-за поддержки устаревших браузеров, которая требовалась многим разработчикам. В будущем Canvas может быть упразднен или превращен во внешний плагин, потому что поддержка браузеров улучшилась, а поддержка холста сдерживает нас. Для Pixi будущее больше за WebGL 1 против 2, чем за холстом против WebGL.

Тем не менее, для v5 не так много изменилось. Мы создали два «пакета» pixi: один с холстом и один без. Тот, что с холстом, называется «pixi.js-legacy», а только webgl — «pixi.js».

Возвращаясь к вашему исходному вопросу, autoDetectRenderer есть только в pixi.js-legacy, а не в пакете по умолчанию. Мы пока не нашли лучшего способа указать это в документации, но, надеюсь, исправим до релизов v5 (PR приветствуются!)

Кроме того, мы очень близки к выпуску RC для v5, который может произойти где-то в течение следующих нескольких недель. Я бы отложил принятие v5 до ее выхода или использовал бы то, что есть в ветке разработки. Большинство API остались прежними: Sprite, Container, DisplayObject, Text в основном те же самые. Большинство изменений в v5 — это введение API среднего уровня для людей, которые хотят делать что-то ближе к WebGL или создавать свой собственный рендеринг.

Надеюсь, это поможет объяснить.
0
383 / 23 / 2
Регистрация: 12.06.2021
Сообщений: 211
Записей в блоге: 2
30.05.2025, 02:58
8Observer8, можете работу с

const app = new PIXI.Application
разместить на песочнице и оставить ссылку? Не одного нормального примера не нашла
0
9945 / 2946 / 496
Регистрация: 05.10.2013
Сообщений: 8,016
Записей в блоге: 241
30.05.2025, 12:30
Пример выше https://jsfiddle.net/bigtimebuddy/t1u9678x/ перенёс в более лучшую песочницу: https://plnkr.co/edit/ef1KmVMMd9nDfwKd, где можно сделать намного более наглядное и естественное подключение внешних файлов:

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.0">
    <title>Pixi v7 legacy canvas force</title>
</head>
 
<body>
    <canvas id="cv"></canvas>
    <script src="https://pixijs.download/fix/canvas-renderer-view/pixi-legacy.js"></script>
    <script 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
//use pixi.js 7.0.4 and pixi-legacy.js 7.0.4
// cannot appear canvas if following option specified forceCanvas: true and specify view
const app = new PIXI.Application({
    view: document.querySelector("#cv"),
  forceCanvas:true 
});
 
//but, appear canvas if appendChild app.view after initialize application.
//document.body.appendChild(app.view);
 
// Draw a shape (for check display)
const shape = new PIXI.Graphics();
app.stage.addChild(shape);
 
shape
  .beginFill(0xff0000)
  .drawRect(0,0,100,100);
Песочница Plunker (https://plnkr.co/) лучше тем, что позволяет:
  • Создавать отдельные файлы .js, .html, .css и т.д.
  • Можно загружать файлы перетаскиванием мыши. Можно выделить .js файлы своего локального проекта в папке на своём компьютере и перетащить в Plunker. Это намного быстрее, чем переместить проект из нескольких файлов на JSFiddle
  • Можно загружать на Plunker спрайты, звуковые файлы, JSON и т.д.
  • Проект выглядит так, как он бы выглядел, если вы работаете с ним локально в Sublime Text 4, VSCode и т.д. Размещение проекта намного быстрее, чем на JSFiddle, потому что вам достаточно перетащить мышкой все js-файлы и index.html, чем пытаться всё скопировать в один файл, чтобы разместить на JSFiddle
  • Проект с созданными примером можно скачать в виде архива (правой кнопкой по корню проекта и выбрать "Download as...") и разместить сразу на каком-нибудь бесплатном хостинге. Например, можно перетащить мышкой, например, скаченную с Plunker папку, на бесплатный хостинг https://www.netlify.com/ Каждый загруженный проект на Netlify получает свой URL-адрес с приставкой .netlify.app Например: https://warrior-animations-sdl3.netlify.app
1
383 / 23 / 2
Регистрация: 12.06.2021
Сообщений: 211
Записей в блоге: 2
11.06.2025, 16:08
Скачала версию pixi 4.5.6. Там есть поддержка Canvas. Версия выбрана специально для тестирования Canvas, чтобы проверить как drawTriangles будет работать. Всего сделала четыре примера. По сути они похожи, только координаты точек изменены.
Первый пример Webgl для создания приложения используется функция.
JavaScript
1
2
3
 const app = new PIXI.Application(800, 600, {
    backgroundColor: 0x1099bb
  });
Второй пример Canvas используется функция.
JavaScript
1
2
3
4
const app = new PIXI.CanvasRenderer(800, 600, {
    backgroundColor: 0x1099bb,
    view: document.getElementById('game-canvas') // или просто добавить на страницу
});
Для Canvas нужно ещё добавить тег canvas.
При тестировании обе функции отработали нормально. Вот исходники.
Pixi1.zip

Теперь flash, там можно изменить координаты так, что лини будут пересекаться, а расположение точек окажутся в случайных местах, что может нарушить отрисовку. Но на flash это никак не повлияет. Проверено, всё работает нормально. Сделаем тоже самое на Pixi, используем WebGL и Canvas. Пример 3 и 4.
Вот код Example3 на Webgl.
HTML5
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
<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="UTF-8" />
  <title>PixiJS v4.5.6 — Mesh вместо SimpleMesh</title>
  <style> body { margin: 0; } canvas { display: block; } </style>
</head>
<body>
 
<!-- Подключаем PixiJS v4.5.6 https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.5.6/pixi.js-->
<script src="../libs/pixi.js"></script> 
 
<script>
  // Создаём приложение
  const app = new PIXI.Application(800, 600, {
    backgroundColor: 0x1099bb
  });
  document.body.appendChild(app.view);
 
 
 const vertices = [196.38440032645163,-96.62102519267636,
                         103.37009957214813,-103.62387441434305,
                         -103.37009957214813,103.62387441434305,
                         96.38440032645163,96.62102519267636,
                         120,120,
                         120,240,
                         240,0,
                         240,120,
                         240,240
  ];
 
  const uvtData = [0,0,
                                       0.9662102519267636,1,
                                       0,1.0362387441434304,
                                       1,1,
                                       1.0362387441434304,0,
                                       1,0.9662102519267636,
                                       1,0,
                                       1,0.5,
                                       1,1
  ];
 
  const indices = [0,1,3,
                                    1,2,3,
                                    1,4,2,
                                    4,2,5,
                                    3,6,4,
                                    6,4,7,
                                    4,7,5,
                                    7,5,8
  ];
 
 const uvs = uvtData;
 
  // Загружаем текстуру
  PIXI.loader
    .add("archer", "archer.jpg")
    .load(setup);
 
  function setup(loader, resources) {
    const texture = resources.archer.texture;
 
  
 
    // Создаём меш вручную
    const mesh = new PIXI.mesh.Mesh(
      texture,
      //vertices,
     // uvs,
      //indices,
       new Float32Array(vertices),
       new Float32Array(uvs),
      new Uint16Array(indices),
      PIXI.mesh.Mesh.DRAW_MODES.TRIANGLES
    );
 
    // Позиционируем
    mesh.position.set(0, 0);
 
    // Добавляем на сцену
    app.stage.addChild(mesh);
    
    
      const points = [];
        for (let i = 0; i < vertices.length; i += 2) {
            const circle = new PIXI.Graphics();
            circle.beginFill(0xff0000);
            circle.drawCircle(0, 0, 6);
            circle.endFill();
            circle.x = vertices[i];
            circle.y = vertices[i + 1];
            circle.interactive = true;
            circle.buttonMode = true;
            circle.vertexIndex = i;
            app.stage.addChild(circle);
            points.push(circle);
            circle
            .on("pointerdown", onDragStart)
            .on("pointerup", onDragEnd)
            .on("pointerupoutside", onDragEnd)
            .on("pointermove", onDragMove);
        }
        
         function onDragStart(event) {
              this.data = event.data;
              this.dragging = true;
            }
 
            function onDragEnd() {
              this.dragging = false;
              this.data = null;
            } 
            function onDragMove() {
                if (this.dragging) {
                    const newPosition = this.data.getLocalPosition(app.stage);
                    //console.log(newPosition);
                    this.x = newPosition.x;
                    this.y = newPosition.y;
                    // Update vertex position in mesh
                    mesh.vertices[this.vertexIndex] = this.x;
                    mesh.vertices[this.vertexIndex + 1] = this.y;
                    // app.render(stage);
                }
            }
  }
</script>
 
</body>
</html>
А вот результат.


Перейдём к Canvas и сделаем тоже самое Example 4.
Вот код.
HTML5
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
<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="UTF-8" />
  <title>PixiJS v4.5.6 — Mesh вместо SimpleMesh</title>
  <style> body { margin: 0; } canvas { display: block; } </style>
</head>
<body>
 
<!-- Подключаем PixiJS v4.5.6 -->
<script src="../libs/pixi.js"></script> 
<canvas id="game-canvas" width="800" height="600">
<script>
 
const app = new PIXI.CanvasRenderer(800, 600, {
    backgroundColor: 0x1099bb,
    view: document.getElementById('game-canvas') // или просто добавить на страницу
});
 
 
  document.body.appendChild(app.view);
 
 
 const vertices = [196.38440032645163,-96.62102519267636,
                         103.37009957214813,-103.62387441434305,
                         -103.37009957214813,103.62387441434305,
                         96.38440032645163,96.62102519267636,
                         120,120,
                         120,240,
                         240,0,
                         240,120,
                         240,240
  ];
 
  const uvtData = [0,0,
                                       0.9662102519267636,1,
                                       0,1.0362387441434304,
                                       1,1,
                                       1.0362387441434304,0,
                                       1,0.9662102519267636,
                                       1,0,
                                       1,0.5,
                                       1,1
  ];
 
  const indices = [0,1,3,
                                    1,2,3,
                                    1,4,2,
                                    4,2,5,
                                    3,6,4,
                                    6,4,7,
                                    4,7,5,
                                    7,5,8
  ];
 
 
const stage = new PIXI.Container();
 const uvs = uvtData;
 
  // Загружаем текстуру
  PIXI.loader
    .add("archer", "archer.jpg")
    .load(setup);
 
  function setup(loader, resources) {
    const texture = resources.archer.texture;
 
  
 
    // Создаём меш вручную
    const mesh = new PIXI.mesh.Mesh(
      texture,
      //vertices,
     // uvs,
      //indices,
       new Float32Array(vertices),
       new Float32Array(uvs),
       new Uint16Array(indices),
      PIXI.mesh.Mesh.DRAW_MODES.TRIANGLES
    );
 
    // Позиционируем
    mesh.position.set(0, 0);
     stage.addChild(mesh);
     
     
     
      const points = [];
        for (let i = 0; i < vertices.length; i += 2) {
            const circle = new PIXI.Graphics();
            circle.beginFill(0xff0000);
            circle.drawCircle(0, 0, 6);
            circle.endFill();
            circle.x = vertices[i];
            circle.y = vertices[i + 1];
            circle.interactive = true;
            circle.buttonMode = true;
            circle.vertexIndex = i;
            stage.addChild(circle);
            points.push(circle);
            circle
            .on("pointerdown", onDragStart)
            .on("pointerup", onDragEnd)
            .on("pointerupoutside", onDragEnd)
            .on("pointermove", onDragMove);
        }
        
        function onDragStart(event) {
              this.data = event.data;
              this.dragging = true;
            }
 
            function onDragEnd() {
              this.dragging = false;
              this.data = null;
            } 
            function onDragMove() {
                if (this.dragging) {
                    const newPosition = this.data.getLocalPosition(stage);
                    console.log(newPosition);
                    this.x = newPosition.x;
                    this.y = newPosition.y;
                    // Update vertex position in mesh
                    mesh.vertices[this.vertexIndex] = this.x;
                    mesh.vertices[this.vertexIndex + 1] = this.y;
                     app.render(stage);
                }
            }  
     
      app.render(stage);
    // Добавляем на сцену
    //app.stage.addChild(mesh);
  }
</script>
 
</body>
</html>
Результат отличается. Используя Canvas некоторые части текстуры пропали.


Исходники Example 3 и Example4.
Pixi2.zip

Интересно, что WebGL Pixi 4.5.6 работает только в старых браузерах, а в новых та же ситуация что и с Canvas пропадают текстуры. Например два примера Example3 и Example4 я тестировала в Opera 79 и всё работала. Когда запустила через Google Chrome текстуры пропали, что на WebGL, что на Canvas. Предположительно какие-то функции WebGL отменили с новыми версиями и поддерживаются только на старых браузерах, но если взять другую библиотеку где есть работа с WebGL и можно нарисовать drawTrinagles то там всё работает. Пока не знаю в чём отличия работы в новых и старых браузерах. Библиотеку pixi пока ещё не разбирала.

Итог: WebGL это технология в браузере которая использует всю мощь видеокарты для рисования очень крутой 3d-графики. Если например чтобы сделать простую двухмерную игру достаточно использовать Canvas API, то для более сложных проектов нужен WebGL.

Почему часть текстур на Canvas пропадает? Как уже упоминалась Canvas API используется только для рисование простых игр и объектов. Собрав не много информации в интернете про drawTrinangles удалось выяснить, что это первый способ реализовать 3d на движке 2d. Например, чтобы сделать поворот объекта в 3d, нужно поменять UV-координаты и позиции треугольника. Об этом даже есть статья в интернете как сделать 3d используя drawTrinangles.

Из этого сделала вывод текстуры попадают в Canvas API потому, что холст не предназначен для 2-х мерной графики и поэтому при сложных координатах drawTriangles работает некорректно.

Вывод: если в проекте используются функции отдалённо напоминающий рендеринг 3d то лучше использовать WebGL. Это технология и быстрее и надёжнее. Можно делать крутые 3d игры.
0
9945 / 2946 / 496
Регистрация: 05.10.2013
Сообщений: 8,016
Записей в блоге: 241
11.06.2025, 17:20
Цитата Сообщение от Olga28 Посмотреть сообщение
Можно делать крутые 3d игры
Команда из РФ сделала вот эту игру с мультиплеером: https://vectaria.io/home Я не искал какие есть ещё браузерные игры. Есть огромное количество встроенных браузерных игр в социальные сети. Значит, есть люди, которые играю в них, есть люди, которые делают браузерные игры и как-то зарабатывают на них. Обычно игры делают командами, а одиночки это редкость. Перед тем как попасть в команду, нужно иметь опыт, а без команды можно получать опыт, создавая игровые демки известных игр и для этого не нужен графический дизайнер, гейм дизайнер, потому что известные игры уже имеют ассеты в интернете и их геймплей известен. В команде проще всего получить опыт в геймдев, если изучить основы движка Unity и пойти стажёром в офис на мобильную разработку игр на Unity. В офисе проще учиться на реальных проектах имея живое общение с сотрудниками. Браузерные игры - это скорее всего, будет удалёнка, что посложнее. Я не узнавал, может в крупных городах есть офисы с созданием браузерных игр.

Цитата Сообщение от Olga28 Посмотреть сообщение
Например, чтобы сделать поворот объекта в 3d, нужно поменять UV-координаты и позиции треугольника.
Чтобы повернуть объект в 2D и 3D нужно умножить матрицу поворота на каждую вершину каждого треугольника. Пример в 2D с поворотом прямоугольника в сообщении #4

Цитата Сообщение от Olga28 Посмотреть сообщение
Если например чтобы сделать простую двухмерную игру достаточно использовать Canvas API, то для более сложных проектов нужен WebGL.
Для простых тоже можно использовать WebGL, чтобы учиться на простых 2D играх. У WebGL огромное количество преимущество, как по отношению к Canvas, так и по отношению к OpenGL (C, C++, C#, Java и т.д.), так и по отношению к WebGPU. WebGL прозрачен в понимании, как используется линейная алгебра, а в Canvas API или у Pixi.js математика вся скрыта и сложно в это вмешаться, а WebGL, как напильник, которым можно тонко что-то подогнать. Если сравнивать Desktop и Web, то на веб намного проще сделать GUI с помощью HTML и CSS. Проще работать с 3D звуком на Web Audio API. Проще работать с мультиплеером и кооперативом за счёт веб-сокетов. Проще тренироваться делать клиент-серверные приложения и хостить их бесплатно на Render.com В целом JS проще, чем другие языки для работы с OpenGL. Просто не надо стразу браться за сложные игры, а нужно тренироваться на маленьки - сделать сначала Крестики-Нолики по сети на веб-сокетах и залить на Render.com, чтобы два человека могли играть против друг друга по интернету. Тренироваться на других маленьких известтых играх - Змейка, Арканоид, Пак-Ман. Использовать Box2D для управления персонажем и определения коллизий. Пример на Three.js: Рисование коллайдеров Box2D v2 на Three.js с помощью порта @box2d/core
0
9945 / 2946 / 496
Регистрация: 05.10.2013
Сообщений: 8,016
Записей в блоге: 241
29.06.2025, 15:20
Цитата Сообщение от Olga28 Посмотреть сообщение
Предположительно какие-то функции WebGL отменили с новыми версиями и поддерживаются только на старых браузерах
На старых браузерах без проблем работает WebGL 1.0 на Windows XP и Windows 7, а WebGL 2.0 не работает. Разница между 1.0 и 2.0 в том, что WebGL 1.0 основан на OpenGL ES 2.0, а WebGL 2.0 основан на OpenGL ES 3.0



Можете в ChatGPT написать в чём разница между WebGL 1.0 и WebGL 2.0 и он вам подробнее напишет. Я считаю, что вполне хватит для большинства задач WebGL 1.0. Эта версия будет запускаться не только на очень старых Desktop браузерах, но и на очень старых мобильных браузерах на Android.

В WebGL нет ничего сложного. В дальнейшем это даже проще, чем работать с Pixi.js Готовый фреймворк только в начале даёт преимущество, а дальше он только мешает, а на чистом WebGL лучше понимание, что как работает и больше простора для допиливания напильником. Pixi.js - это только 2D, а чистый WebGL - это кроме 2D ещё и 3D, к которому легко прийти из 2D. Если вам нужен 3D с PBR, то конечно, проще взять Three.js, но чистый WebGL даст понимание, как работает Three.js, потому что Three.js написана с помощью чистого WebGL. Если вы хотите использовать Pixi.js, то вам будет всё равно очень полезно иногда изучать чистый WebGL, чтобы понимать как работает Pixi.js, как работает линейная алгебра на glMatrix, как работают основы компьютерной графики на шейдерах. Когда вы узнаете основы WebGL на практике, то вам будет проще писать свои шейдеры для Pixi.js

Я постарался подробно объяснить, как работает рисование треугольника на шейдерном OpenGL и Qt C++. На WebGL и JavaScript будет тот же самый принцип работы. Преимущество WebGL в том, что программы которые использую OpenGL и WebGL выглядят на всех языках очень похоже. Например, вы можете веб-версию своего приложения делать на WebGL и JavaScript, а EXE делать на Delphi, который вы тоже изучали или изучаете. Вам будет легко одновременно дописывать программы на JavaScript и Delphi, потому что они будут выглядить один в один на OpenGL и WebGL.

Посмотрите, пожалуйста, до конца моё видео. Я постарался объяснить своими словами максимально доступно. Я использовал функции обёртки Qt над OpenGL, но главное, это суть работы шейдеров и матриц. На WebGL будет очень похоже. Позже я запишу, как с нуля написать трансформированный треугольник на WebGL и JavaScript.

На русском:



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

0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
29.06.2025, 15:20
Помогаю со студенческими работами здесь

Функция, очень похожая на switch
Здравствуйте, подскажите кто знает функцию как switch(), только чтобы всё не зависило от одной переменной, то есть у меня есть набор...

Функция похожая на splice из JavaScript
Здравствуйте, я раньше работала в JavaScript, там была функция по удалению массива splice, подскажите существует похожий вариант функции на...

Функция одного параметра похожая на логарифм
Нужна функция одного параметра принимающая вход от 0 до 1 и возвращающая от 0 до 1 по похожему закону Резко повышает малые значения и...

Есть функция в С++ похожая на: DEL(St, Poz, N)
Решил немного переписать код: static const size_t Capacity = 8; static const string Name = { &quot;CIV4GameText_Colonization.xml&quot;,...

Публикация из flash в html5.
Всем привет! Подскажите пожалуйста можно ли в момент сохранения флеш-проекта сайта, сохранить его в html?


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Идея фильтра интернета (сервер = слой+фильтр).
Hrethgir 31.03.2026
Суть идеи заключается в том, чтобы запустить свой сервер, о чём я если честно мечтал давно и давно приобрёл книгу как это сделать. Но не было причин его запускать. Очумелые учёные напечатали на. . .
Модель здравосоХранения 6. ESG-повестка и устойчивое развитие; углублённый анализ кадрового бренда
anaschu 31.03.2026
В прикрепленном документе раздумья о том, как можно поменять модель в будущем
10 пpимет, которые всегда сбываются
Maks 31.03.2026
1. Чтобы, наконец, пришла маршрутка, надо закурить. Если сигарета последняя, маршрутка придет еще до второй затяжки даже вопреки расписанию. 2. Нaдоели зима и снег? Не надо переезжать. Достаточно. . .
Перемещение выделенных строк ТЧ из одного документа в другой
Maks 31.03.2026
Реализация из решения ниже выполнена на примере нетипового документа "ВыдачаОборудованияНаСпецтехнику" с единственной табличной частью "ОборудованиеИКомплектующие" разработанного в конфигурации КА2. . . .
Functional First Web Framework Suave
DevAlt 30.03.2026
Sauve. IO Апнулись до NET10. Из зависимостей один пакет, работает одинаково хорошо как в режиме проекта так и в интерактивном режиме. из сложностей - чисто функциональный подход. Решил. . .
Автоматическое создание документа при проведении другого документа
Maks 29.03.2026
Реализация из решения ниже выполнена на нетиповых документах, разработанных в конфигурации КА2. Есть нетиповой документ "ЗаявкаНаРемонтСпецтехники" и нетиповой документ "ПланированиеСпецтехники". В. . .
Настройка движения справочника по регистру сведений
Maks 29.03.2026
Решение ниже реализовано на примере нетипового справочника "ТарифыМобильнойСвязи" разработанного в конфигурации КА2, с целью учета корпоративной мобильной связи в коммерческом предприятии. . . .
Автозаполнение реквизита при выборе элемента справочника
Maks 27.03.2026
Программный код из решения ниже на примере нетипового документа "ЗаявкаНаРемонтСпецтехники" разработанного в конфигурации КА2. При выборе "Спецтехники" (Тип Справочник. Спецтехника), заполняется. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru