Форум программистов, компьютерный форум, киберфорум
Python: GUI, графика
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.73/22: Рейтинг темы: голосов - 22, средняя оценка - 4.73
3 / 3 / 0
Регистрация: 04.11.2018
Сообщений: 123

Непрерывное движение obj модели вверх-вниз

22.01.2021, 00:42. Показов 4253. Ответов 10

Студворк — интернет-сервис помощи студентам
Здравствуйте уважаемые!

Столкнулся с проблемой, не могу заставить свою obj модель двигаться вниз вверх непрерывно на заданную высоту. Обычная анимация короче. То есть поднимается на 10, затем спускается на 10 и т.д.

Вылезают такие ошибки:
Traceback (most recent call last):
File "...", line 258, in <module>
main()
File "...", line 166, in main
meduza_matrix.for_translate('y', meduza_height)
AttributeError: 'matrix' object has no attribute 'for_translate'

Ошибка именно в этой строке: meduza_matrix.translate('y', meduza_height)
То есть я так понимаю что к meduza_matrix нельзя применить translate, но что тогда сделать чтобы можно было не понимаю :/


Пытаюсь сделать это движение через матрицу так:
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
meduza_matrix = np.mat(np.eye(100))
    meduza_height = 0
    meduza_raise = true
 
    if meduza_raise:
        meduza_height += 1
        meduza_matrix.translate('y', meduza_height)
        if meduza_height == 10:
            meduza_raise == false
    else:
        meduza_height -= 1
        meduza_matrix.translate('y', meduza_height)
        if meduza_height == -10:
            meduza_raise == true
 
meduza_vao = glGenVertexArrays(1)
    glBindVertexArray(meduza_vao)
    meduza_vbo = glGenBuffers(1)
    glBindBuffer(GL_ARRAY_BUFFER, meduza_vbo)
    glBufferData(GL_ARRAY_BUFFER, meduza.model.itemsize * len(meduza.model),
                 meduza_matrix * meduza.model, GL_STATIC_DRAW)
    # position
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, meduza.model.itemsize * 3, ctypes.c_void_p(0))
    glEnableVertexAttribArray(0)
    # textures
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, meduza.model.itemsize * 2, ctypes.c_void_p(meduza_texture_offset))
    glEnableVertexAttribArray(1)
    glBindVertexArray(0)
Может кто знает как мне можно сделать эту анимацию, а то я уже всю голову сломал
Подскажите пожалуйста, буду очень благодарен)
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
22.01.2021, 00:42
Ответы с готовыми решениями:

Движение точки вверх - вниз
.code start: mov ax, 0013h ; int 10h ; ;--------------тело проги tochka: MOV AH,0ch

ActiveRecord треверсинг вверх и вниз по модели MySQL
Предположим, что есть модель: И есть результат запроса ActiveRecord который закеширован в MySQL - Данные в таблицах не меняются(или...

Движение картинки pictureBox вниз и вверх
Как сделать движение по экрану картинки вверх и вниз при запуске программы? Запустил я программу и началось движение картинки вниз и вверх...

10
5515 / 2868 / 571
Регистрация: 07.11.2019
Сообщений: 4,758
22.01.2021, 06:50
Так .for_translate или .translate вы вызываете?
0
3 / 3 / 0
Регистрация: 04.11.2018
Сообщений: 123
22.01.2021, 12:04  [ТС]
u235, а там без разницы, и то и то пробовал вызывать ошибка та же
AttributeError: 'matrix' object has no attribute 'translate'.

Добавлено через 2 минуты
u235, может есть какой-то другой способ такой анимации, если уж через матрицу не получается?
Смотрел через pygame, но не смог разобраться, как его конкретно к моей 3d obj-модели применить
0
5515 / 2868 / 571
Регистрация: 07.11.2019
Сообщений: 4,758
22.01.2021, 16:30
Космодемьян, запустите в режиме отладки и смотрите что у вас происходит и почему ошибка.
Так как вы привели неполный код и не приложили obj, то разбирайтесь самостоятельно. Удачи.
0
9933 / 2936 / 494
Регистрация: 05.10.2013
Сообщений: 7,966
Записей в блоге: 217
22.01.2021, 18:07
Лучший ответ Сообщение было отмечено Космодемьян как решение

Решение

Цитата Сообщение от Космодемьян Посмотреть сообщение
Может кто знает как мне можно сделать эту анимацию, а то я уже всю голову сломал
Подскажите пожалуйста, буду очень благодарен)
Я могу вам предложить свою посильную помощь в переписывании вашего примера на PyQt5 или на PySide2. В эти фреймворки встроена удобная лёгкая обёртка над матрицами и OpenGL.

Написал очень короткий пример на PyQt5 и PySide2, который просто выводит на экран матрицу после применения метода translate:

Python
1
2
3
4
5
6
    def initializeGL(self):
        gl.glClearColor(0.2, 0.2, 0.2, 1)
        gl.glEnable(gl.GL_DEPTH_TEST)
        self.matrix = QMatrix4x4()
        self.matrix.translate(QVector3D(2, 3, 5))
        print(self.matrix)
PyQt5

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
import sys
 
from OpenGL import GL as gl
from PyQt5.QtWidgets import QApplication, QOpenGLWidget
from PyQt5.QtGui import QMatrix4x4, QVector3D
from PyQt5.QtCore import Qt
 
class Window(QOpenGLWidget):
 
    def __init__(self):
        super().__init__()
        self.setWindowTitle("PyQt5")
        self.resize(400, 400)
 
    def initializeGL(self):
        gl.glClearColor(0.2, 0.2, 0.2, 1)
        gl.glEnable(gl.GL_DEPTH_TEST)
        self.matrix = QMatrix4x4()
        self.matrix.translate(QVector3D(2, 3, 5))
        print(self.matrix)
 
    def paintGL(self):
        gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
 
def main():
    QApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
    app = QApplication(sys.argv)
    w = Window()
    w.show()
    sys.exit(app.exec_())
 
if __name__ == "__main__":
    main()


PySide2
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
import sys
 
from OpenGL import GL as gl
from PySide2.QtWidgets import QApplication, QOpenGLWidget
from PySide2.QtGui import QMatrix4x4, QVector3D
from PySide2.QtCore import Qt
 
class Window(QOpenGLWidget):
 
    def __init__(self):
        super().__init__()
        self.setWindowTitle("PySide2")
        self.resize(400, 400)
 
    def initializeGL(self):
        gl.glClearColor(0.2, 0.2, 0.2, 1)
        gl.glEnable(gl.GL_DEPTH_TEST)
        self.matrix = QMatrix4x4()
        self.matrix.translate(QVector3D(2, 3, 5))
        print(self.matrix)
 
    def paintGL(self):
        gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
 
def main():
    QApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
    app = QApplication(sys.argv)
    w = Window()
    w.show()
    sys.exit(app.exec_())
 
if __name__ == "__main__":
    main()


Пример, как нарисовать треугольник:
  • PyQt5: https://rextester.com/KWYGH93003
    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
    
    import sys
    import numpy as np
    from OpenGL import GL as gl
    from PyQt5.QtWidgets import QOpenGLWidget, QApplication
    from PyQt5.QtGui import (QOpenGLBuffer, QOpenGLShaderProgram,
        QOpenGLShader)
    from PyQt5.QtCore import Qt
     
    class OpenGLWidget(QOpenGLWidget):
        def __init__(self):
            super().__init__()
            self.setWindowTitle("Triangle, PyQt5, OpenGL 3.3")
            self.resize(400, 400)
        def initializeGL(self):
            gl.glClearColor(0.5, 0.8, 0.7, 1.0)
            vertShaderSrc = """
                #version 330 core
                in vec3 aPosition;
                void main()
                {
                    gl_Position = vec4(aPosition, 1.0);
                }
            """
            fragShaderSrc = """
                #version 330 core
                void main()
                {
                    gl_FragColor = vec4(0.5, 0.2, 0.9, 1.0);
                }
            """
            program = QOpenGLShaderProgram(self)
            program.addShaderFromSourceCode(QOpenGLShader.Vertex, vertShaderSrc)
            program.addShaderFromSourceCode(QOpenGLShader.Fragment, fragShaderSrc)
            program.link()
            program.bind()
            vertPositions = np.array([
                -0.5, -0.5, 0.0,
                0.5, -0.5, 0.0,
                0.0, 0.5, 0.0], dtype=np.float32)
            self.vertPosBuffer = QOpenGLBuffer()
            self.vertPosBuffer.create()
            self.vertPosBuffer.bind()
            self.vertPosBuffer.allocate(vertPositions, len(vertPositions) * 4)
            program.bindAttributeLocation("aPosition", 0)
            program.setAttributeBuffer(0, gl.GL_FLOAT, 0, 3)
            program.enableAttributeArray(0)
     
        def paintGL(self):
            gl.glClear(gl.GL_COLOR_BUFFER_BIT)
            gl.glDrawArrays(gl.GL_TRIANGLES, 0, 3)
     
    def main():
        QApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
        a = QApplication(sys.argv)
        w = OpenGLWidget()
        w.show()
        sys.exit(a.exec_())
     
    if __name__ == "__main__":
        main()
  • PySide2: https://rextester.com/RDHCF22516
    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
    
    import sys
    import numpy as np
    from OpenGL import GL as gl
    from PySide2.QtWidgets import QOpenGLWidget, QApplication
    from PySide2.QtGui import (QOpenGLBuffer, QOpenGLShaderProgram,
        QOpenGLShader)
    from PySide2.QtCore import Qt
     
    class OpenGLWidget(QOpenGLWidget):
        def __init__(self):
            super().__init__()
            self.setWindowTitle("Triangle, PySide2, OpenGL 3.3")
            self.resize(400, 400)
        def initializeGL(self):
            gl.glClearColor(0.5, 0.8, 0.7, 1.0)
            vertShaderSrc = """
                #version 330 core
                in vec3 aPosition;
                void main()
                {
                    gl_Position = vec4(aPosition, 1.0);
                }
            """
            fragShaderSrc = """
                #version 330 core
                void main()
                {
                    gl_FragColor = vec4(0.5, 0.2, 0.9, 1.0);
                }
            """
            program = QOpenGLShaderProgram(self)
            program.addShaderFromSourceCode(QOpenGLShader.Vertex, vertShaderSrc)
            program.addShaderFromSourceCode(QOpenGLShader.Fragment, fragShaderSrc)
            program.link()
            program.bind()
            vertPositions = np.array([
                -0.5, -0.5, 0.0,
                0.5, -0.5, 0.0,
                0.0, 0.5, 0.0], dtype=np.float32)
            self.vertPosBuffer = QOpenGLBuffer()
            self.vertPosBuffer.create()
            self.vertPosBuffer.bind()
            self.vertPosBuffer.allocate(vertPositions, len(vertPositions) * 4)
            program.bindAttributeLocation("aPosition", 0)
            program.setAttributeBuffer(0, gl.GL_FLOAT, 0, 3)
            program.enableAttributeArray(0)
     
        def paintGL(self):
            gl.glClear(gl.GL_COLOR_BUFFER_BIT)
            gl.glDrawArrays(gl.GL_TRIANGLES, 0, 3)
     
    def main():
        QApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
        a = QApplication(sys.argv)
        w = OpenGLWidget()
        w.show()
        sys.exit(a.exec_())
     
    if __name__ == "__main__":
        main()
3
9933 / 2936 / 494
Регистрация: 05.10.2013
Сообщений: 7,966
Записей в блоге: 217
23.01.2021, 15:15
Раз вам понравился мой ответ, то дарю вам пример кубика, откуда вы можете взять базу для 3D, в том числе шейдеры для базового освещения:

Кубик в 3D:
  • PyQt5: https://rextester.com/VIQC38551
    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
    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
    
    import sys
    import numpy as np
    from OpenGL import GL as gl
    from PyQt5.QtWidgets import QApplication, QOpenGLWidget
    from PyQt5.QtGui import (QOpenGLShaderProgram, QOpenGLShader,
        QOpenGLBuffer, QMatrix4x4, QVector3D)
    from PyQt5.QtCore import Qt
     
    class OpenGLWidget(QOpenGLWidget):
        def __init__(self):
            super().__init__()
            self.setWindowTitle("PyQt5, OpenGL")
            self.resize(268, 268)
        def initializeGL(self):
            gl.glClearColor(0.5, 0.8, 0.7, 1.0)
            gl.glEnable(gl.GL_DEPTH_TEST)
            vertShaderSrc = """
                    #version 330 core
                    in vec3 aPosition;
                    in vec4 aNormal;
                    uniform mat4 uMvpMatrix;
                    uniform mat4 uNormalMatrix;
                    out vec4 vColor;
                    void main()
                    {
                        gl_Position = uMvpMatrix * vec4(aPosition, 1.0);
                        vec3 lightDirection = normalize(vec3(0.0, 0.5, 0.7));
                        vec4 color = vec4(1.0, 0.4, 0.0, 1.0);
                        vec3 normal = normalize((uNormalMatrix * aNormal).xyz);
                        float nDotL = max(dot(normal, lightDirection), 0.0);
                        vColor = vec4(color.rgb * nDotL + vec3(0.1), color.a);
                    }
            """
            fragShaderSrc = """
                    #version 330 core
                    in vec4 vColor;
                    out vec4 fragColor;
                    void main()
                    {
                        fragColor = vColor;
                    }
            """
            self.program = QOpenGLShaderProgram()
            self.program.addShaderFromSourceCode(QOpenGLShader.Vertex, vertShaderSrc)
            self.program.addShaderFromSourceCode(QOpenGLShader.Fragment, fragShaderSrc)
            self.program.link()
            self.program.bind()
            self.amountOfVertices = self.initVertexBuffers()
            self.projMatrix = QMatrix4x4()
            self.viewMatrix = QMatrix4x4()
            self.viewMatrix.lookAt(
                QVector3D(20, 15, 30),
                QVector3D(0, 0, 0),
                QVector3D(0, 1, 0))
            self.modelMatrix = QMatrix4x4()
            self.modelMatrix.translate(QVector3D(0, 0, 0))
            self.modelMatrix.rotate(0, QVector3D(0, 1, 0))
            self.modelMatrix.scale(7, 7, 7)
            self.normalMatrix = QMatrix4x4()
        def paintGL(self):
            gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
            self.drawBox()
        def drawBox(self):
            mvpMatrix = self.projMatrix * self.viewMatrix * self.modelMatrix
            self.program.bind()
            self.program.setUniformValue("uMvpMatrix", mvpMatrix)
            self.normalMatrix = self.modelMatrix.inverted()
            self.normalMatrix = self.normalMatrix[0].transposed()
            self.program.setUniformValue("uNormalMatrix", self.normalMatrix)
            gl.glDrawElements(gl.GL_TRIANGLES, self.amountOfVertices, gl.GL_UNSIGNED_INT, None)
        def resizeGL(self, w, h):
            gl.glViewport(0, 0, w, h)
            self.projMatrix.setToIdentity()
            self.projMatrix.perspective(50, float(w)/float(h), 0.1, 100)
        def initVertexBuffers(self):
            # Create a cube
            #    v6----- v5
            #   /|      /|
            #  v1------v0|
            #  | |     | |
            #  | |v7---|-|v4
            #  |/      |/
            #  v2------v3
            vertPositions = np.array([
                # v0-v1-v2-v3 front
                1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0,
                # v0-v3-v4-v5 right
                1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0,
                # v0-v5-v6-v1 up
                1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0,
                # v1-v6-v7-v2 left
                -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0,
                # v7-v4-v3-v2 down
                -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0,
                # v4-v7-v6-v5 back
                1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0
            ], dtype=np.float32)
            self.vertPosBuffer = QOpenGLBuffer()
            self.vertPosBuffer.create()
            self.vertPosBuffer.bind()
            self.vertPosBuffer.allocate(vertPositions, len(vertPositions) * 4)
            self.program.bindAttributeLocation("aPosition", 0)
            self.program.setAttributeBuffer(0, gl.GL_FLOAT, 0, 3)
            self.program.enableAttributeArray(0)
            normals = np.array([
                # v0-v1-v2-v3 front
                0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0,
                # v0-v3-v4-v5 right
                1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0,
                # v0-v5-v6-v1 up
                0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,
                # v1-v6-v7-v2 left
                -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0,
                # v7-v4-v3-v2 down
                0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0,
                # v4-v7-v6-v5 back
                0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0
            ], dtype=np.float32)
            self.normalBuffer = QOpenGLBuffer()
            self.normalBuffer.create()
            self.normalBuffer.bind()
            self.normalBuffer.allocate(normals, len(normals) * 4)
            self.program.bindAttributeLocation("aNormal", 1)
            self.program.setAttributeBuffer(1, gl.GL_FLOAT, 0, 3)
            self.program.enableAttributeArray(1)
            indices = np.array([
                0, 1, 2, 0, 2, 3,           # front
                4, 5, 6, 4, 6, 7,           # right
                8, 9, 10, 8, 10, 11,        # up
                12, 13, 14, 12, 14, 15,     # left
                16, 17, 18, 16, 18, 19,     # down
                20, 21, 22, 20, 22, 23      # back
            ])
            self.indexBuffer = QOpenGLBuffer(QOpenGLBuffer.IndexBuffer)
            self.indexBuffer.create()
            self.indexBuffer.bind()
            self.indexBuffer.allocate(indices, len(indices) * 4)
            return len(indices)
     
    def main():
        QApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
        a = QApplication(sys.argv)
        w = OpenGLWidget()
        w.show()
        sys.exit(a.exec_())
     
    if __name__ == "__main__":
        main()
  • PySide2: https://rextester.com/OWJ98916
    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
    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
    
    import sys
    import numpy as np
    from OpenGL import GL as gl
    from PySide2.QtWidgets import QApplication, QOpenGLWidget
    from PySide2.QtGui import (QOpenGLShaderProgram, QOpenGLShader,
        QOpenGLBuffer, QMatrix4x4, QVector3D)
    from PySide2.QtCore import Qt
     
    class OpenGLWidget(QOpenGLWidget):
        def __init__(self):
            super().__init__()
            self.setWindowTitle("PyQt5, OpenGL")
            self.resize(268, 268)
        def initializeGL(self):
            gl.glClearColor(0.5, 0.8, 0.7, 1.0)
            gl.glEnable(gl.GL_DEPTH_TEST)
            vertShaderSrc = """
                    #version 330 core
                    in vec3 aPosition;
                    in vec4 aNormal;
                    uniform mat4 uMvpMatrix;
                    uniform mat4 uNormalMatrix;
                    out vec4 vColor;
                    void main()
                    {
                        gl_Position = uMvpMatrix * vec4(aPosition, 1.0);
                        vec3 lightDirection = normalize(vec3(0.0, 0.5, 0.7));
                        vec4 color = vec4(1.0, 0.4, 0.0, 1.0);
                        vec3 normal = normalize((uNormalMatrix * aNormal).xyz);
                        float nDotL = max(dot(normal, lightDirection), 0.0);
                        vColor = vec4(color.rgb * nDotL + vec3(0.1), color.a);
                    }
            """
            fragShaderSrc = """
                    #version 330 core
                    in vec4 vColor;
                    out vec4 fragColor;
                    void main()
                    {
                        fragColor = vColor;
                    }
            """
            self.program = QOpenGLShaderProgram()
            self.program.addShaderFromSourceCode(QOpenGLShader.Vertex, vertShaderSrc)
            self.program.addShaderFromSourceCode(QOpenGLShader.Fragment, fragShaderSrc)
            self.program.link()
            self.program.bind()
            self.amountOfVertices = self.initVertexBuffers()
            self.projMatrix = QMatrix4x4()
            self.viewMatrix = QMatrix4x4()
            self.viewMatrix.lookAt(
                QVector3D(20, 15, 30),
                QVector3D(0, 0, 0),
                QVector3D(0, 1, 0))
            self.modelMatrix = QMatrix4x4()
            self.modelMatrix.translate(QVector3D(0, 0, 0))
            self.modelMatrix.rotate(0, QVector3D(0, 1, 0))
            self.modelMatrix.scale(7, 7, 7)
            self.normalMatrix = QMatrix4x4()
        def paintGL(self):
            gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
            self.drawBox()
        def drawBox(self):
            mvpMatrix = self.projMatrix * self.viewMatrix * self.modelMatrix
            self.program.bind()
            self.program.setUniformValue("uMvpMatrix", mvpMatrix)
            self.normalMatrix = self.modelMatrix.inverted()
            self.normalMatrix = self.normalMatrix[0].transposed()
            self.program.setUniformValue("uNormalMatrix", self.normalMatrix)
            gl.glDrawElements(gl.GL_TRIANGLES, self.amountOfVertices, gl.GL_UNSIGNED_INT, None)
        def resizeGL(self, w, h):
            gl.glViewport(0, 0, w, h)
            self.projMatrix.setToIdentity()
            self.projMatrix.perspective(50, float(w)/float(h), 0.1, 100)
        def initVertexBuffers(self):
            # Create a cube
            #    v6----- v5
            #   /|      /|
            #  v1------v0|
            #  | |     | |
            #  | |v7---|-|v4
            #  |/      |/
            #  v2------v3
            vertPositions = np.array([
                # v0-v1-v2-v3 front
                1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0,
                # v0-v3-v4-v5 right
                1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0,
                # v0-v5-v6-v1 up
                1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0,
                # v1-v6-v7-v2 left
                -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0,
                # v7-v4-v3-v2 down
                -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0,
                # v4-v7-v6-v5 back
                1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0
            ], dtype=np.float32)
            self.vertPosBuffer = QOpenGLBuffer()
            self.vertPosBuffer.create()
            self.vertPosBuffer.bind()
            self.vertPosBuffer.allocate(vertPositions, len(vertPositions) * 4)
            self.program.bindAttributeLocation("aPosition", 0)
            self.program.setAttributeBuffer(0, gl.GL_FLOAT, 0, 3)
            self.program.enableAttributeArray(0)
            normals = np.array([
                # v0-v1-v2-v3 front
                0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0,
                # v0-v3-v4-v5 right
                1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0,
                # v0-v5-v6-v1 up
                0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,
                # v1-v6-v7-v2 left
                -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0,
                # v7-v4-v3-v2 down
                0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0,
                # v4-v7-v6-v5 back
                0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0
            ], dtype=np.float32)
            self.normalBuffer = QOpenGLBuffer()
            self.normalBuffer.create()
            self.normalBuffer.bind()
            self.normalBuffer.allocate(normals, len(normals) * 4)
            self.program.bindAttributeLocation("aNormal", 1)
            self.program.setAttributeBuffer(1, gl.GL_FLOAT, 0, 3)
            self.program.enableAttributeArray(1)
            indices = np.array([
                0, 1, 2, 0, 2, 3,           # front
                4, 5, 6, 4, 6, 7,           # right
                8, 9, 10, 8, 10, 11,        # up
                12, 13, 14, 12, 14, 15,     # left
                16, 17, 18, 16, 18, 19,     # down
                20, 21, 22, 20, 22, 23      # back
            ])
            self.indexBuffer = QOpenGLBuffer(QOpenGLBuffer.IndexBuffer)
            self.indexBuffer.create()
            self.indexBuffer.bind()
            self.indexBuffer.allocate(indices, len(indices) * 4)
            return len(indices)
     
    def main():
        QApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
        a = QApplication(sys.argv)
        w = OpenGLWidget()
        w.show()
        sys.exit(a.exec_())
     
    if __name__ == "__main__":
        main()

Мне больше всего понравилась книга, где отлично описывается введение в шейдеры: WebGL. Программирование трехмерной графики | Мацуда Коичи, Ли Роджер. Код в ней на JavaScript, но WebGL - это по сути тоже самое, что и OpenGL, поэтому код переписывать несложно. Главное, что в книге очень доступно изложена теория работы шейдеров и многих других полезных вещей. Примеры из книги в первом сообщении темы: Небольшие примеры на WebGL
2
9933 / 2936 / 494
Регистрация: 05.10.2013
Сообщений: 7,966
Записей в блоге: 217
24.01.2021, 12:29
Я использую формат dae, потому что его легче парсить, так как dae - это XML, а в PyQt5 и PySide2 встроен парсинг XML, и второе - dae позволяет сохранять анимации созданные в Blender.

В этом видео обзорно показан формат dae:
OpenGL Skeletal Animation Tutorial #4: Collada (.dae) Format


Скину пример загрузки объекта из формата dae (Collada) на PyQt5 и PySide2. Может кому-нибудь пригодится.

Название: ad5bdb90-07b6-4c31-a302-26f3940a8a61.png
Просмотров: 141

Размер: 4.2 Кб

Скачать исходники:

Посмотреть исходники:
  • PyQt5: https://rextester.com/LPUC58350
    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
    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
    
    import sys
    import numpy as np
    from OpenGL import GL as gl
    from PyQt5.QtWidgets import QApplication, QOpenGLWidget
    from PyQt5.QtGui import QOpenGLShaderProgram, QOpenGLShader, QOpenGLBuffer
    from PyQt5.QtGui import QOpenGLTexture, QImage
    from PyQt5.QtGui import QMatrix4x4, QVector3D
    from PyQt5.QtXml import QDomDocument, QDomElement
    from PyQt5.QtCore import Qt, QFile, QIODevice
     
    class VertexBuffers:
        vertex_pos_buffer = None
        normal_buffer = None
        tex_coord_buffer = None
        amount_of_vertices = None
     
    class Locations:
        mvp_matrix_location = None
        model_matrix_location = None
        normal_matrix_location = None
     
    class Object3D:
        position = QVector3D(0, 0, 0)
        rotation = QVector3D(0, 0, 0)
        scale = QVector3D(1, 1, 1)
        mvp_matrix = QMatrix4x4()
        model_matrix = QMatrix4x4()
        normal_matrix = QMatrix4x4()
     
        def __init__(self, vert_buffers, locations, texture):
            self.vert_pos_buffer = vert_buffers.vert_pos_buffer
            self.normal_buffer = vert_buffers.normal_buffer
            self.tex_coord_buffer = vert_buffers.tex_coord_buffer
            self.amount_of_vertices = vert_buffers.amount_of_vertices
            
            self.mvp_matrix_location = locations.mvp_matrix_location
            self.model_matrix_location = locations.model_matrix_location
            self.normal_matrix_location = locations.normal_matrix_location
            
            self.texture = texture
     
        def draw(self, program, proj_view_matrix):
            program.bind()
     
            self.vert_pos_buffer.bind()
            program.setAttributeBuffer(0, gl.GL_FLOAT, 0, 3)
            program.enableAttributeArray(0)
     
            self.normal_buffer.bind()
            program.setAttributeBuffer(1, gl.GL_FLOAT, 0, 3)
            program.enableAttributeArray(1)
     
            self.tex_coord_buffer.bind()
            program.setAttributeBuffer(2, gl.GL_FLOAT, 0, 2)
            program.enableAttributeArray(2)
            
            self.model_matrix.setToIdentity()
            self.model_matrix.translate(self.position)
            self.model_matrix.rotate(self.rotation.x(), QVector3D(1, 0, 0))
            self.model_matrix.rotate(self.rotation.y(), QVector3D(0, 1, 0))
            self.model_matrix.rotate(self.rotation.z(), QVector3D(0, 0, 1))
            self.model_matrix.scale(self.scale)
            self.mvp_matrix = proj_view_matrix * self.model_matrix;
            
            self.normal_matrix = self.model_matrix.inverted()
            self.normal_matrix = self.normal_matrix[0].transposed()
            
            program.bind()
            program.setUniformValue(self.mvp_matrix_location, self.mvp_matrix)
            program.setUniformValue(self.model_matrix_location, self.model_matrix)
            program.setUniformValue(self.normal_matrix_location, self.normal_matrix)
            
            self.texture.bind()
     
            gl.glDrawArrays(gl.GL_TRIANGLES, 0, self.amount_of_vertices)
     
    class Window(QOpenGLWidget):
     
        def __init__(self):
            super().__init__()
            self.setWindowTitle("Dae, Collada")
            self.resize(268, 268)
     
        def initializeGL(self):
            gl.glClearColor(0.2, 0.2, 0.2, 1)
            gl.glEnable(gl.GL_DEPTH_TEST)
            vertShaderSrc = """
                #version 330 core
     
                in vec4 aPosition;
                in vec4 aNormal;
                in vec2 aTexCoord;
     
                uniform mat4 uMvpMatrix;
                uniform mat4 uModelMatrix;
                uniform mat4 uNormalMatrix;
     
                out vec3 vPosition;
                out vec3 vNormal;
                out vec2 vTexCoord;
     
                void main()
                {
                    gl_Position = uMvpMatrix * aPosition;
                    vPosition = vec3(uModelMatrix * aPosition);
                    vNormal = normalize(vec3(uNormalMatrix * aNormal));
                    vTexCoord = aTexCoord;
                }
            """
            fragShaderSrc = """
                #version 330 core
     
                const vec3 lightColor = vec3(0.8, 0.8, 0.8);
                const vec3 lightPosition = vec3(5.0, 7.0, 2.0);
                const vec3 ambientLight = vec3(0.3, 0.3, 0.3);
     
                uniform sampler2D uSampler;
     
                in vec3 vPosition;
                in vec3 vNormal;
                in vec2 vTexCoord;
     
                void main()
                {
                    vec4 color = texture2D(uSampler, vTexCoord);
                    vec3 normal = normalize(vNormal);
                    vec3 lightDirection = normalize(lightPosition - vPosition);
                    float nDotL = max(dot(lightDirection, normal), 0.0);
                    vec3 diffuse = lightColor * color.rgb * nDotL;
                    vec3 ambient = ambientLight * color.rgb;
                    gl_FragColor = vec4(diffuse + ambient, color.a);
                }
            """
            self.program = QOpenGLShaderProgram()
            self.program.addShaderFromSourceCode(QOpenGLShader.Vertex, vertShaderSrc)
            self.program.addShaderFromSourceCode(QOpenGLShader.Fragment, fragShaderSrc)
            self.program.link()
            self.program.bind()
            self.program.bindAttributeLocation("aPosition", 0)
            self.program.bindAttributeLocation("aNormal", 1)
            self.program.bindAttributeLocation("aTexCoord", 2)
            locations = Locations()
            self.program.bind()
            locations.mvp_matrix_location = self.program.uniformLocation("uMvpMatrix");
            locations.model_matrix_location = self.program.uniformLocation("uModelMatrix")
            locations.normal_matrix_location = self.program.uniformLocation("uNormalMatrix")
            self.vert_buffers = self.initVertexBuffers("assets/cube.dae")
            self.proj_view_matrix = QMatrix4x4()
            self.proj_matrix = QMatrix4x4()
            self.view_matrix = QMatrix4x4()
            self.view_matrix.lookAt(
                QVector3D(2, 3, 5),
                QVector3D(0, 0, 0),
                QVector3D(0, 1, 0))
            
            self.texture = QOpenGLTexture(QOpenGLTexture.Target2D)
            self.texture.create()
            self.texture.setData(QImage("assets/cube.png"))
            self.texture.setMinMagFilters(QOpenGLTexture.Linear, QOpenGLTexture.Linear)
            self.texture.setWrapMode(QOpenGLTexture.ClampToEdge)
            self.plane = Object3D(self.vert_buffers, locations, self.texture)
            
        def paintGL(self):
            gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
            self.proj_view_matrix = self.proj_matrix * self.view_matrix
            self.plane.draw(self.program, self.proj_view_matrix)
     
        def resizeGL(self, w, h):
            gl.glViewport(0, 0, w, h)
            self.proj_matrix.setToIdentity()
            self.proj_matrix.perspective(50, float(w) / float(h), 0.1, 100)
            
        def initVertexBuffers(self, path):
            xml_doc = QDomDocument()
            file = QFile(path)
            if not file.open(QIODevice.ReadOnly):
                print("Failed to open the file: " + path)
            xml_doc.setContent(file)
            file.close()
            
            vert_pos_array = []
            normal_array = []
            tex_coord_array = []
            index_array = []
            
            root = xml_doc.documentElement()
            dae_elem = root.firstChildElement()
            while not dae_elem.isNull():
                if dae_elem.tagName() == "library_geometries":
                    geom_elem = dae_elem.firstChildElement()
                    if geom_elem.tagName() == "geometry":
                        mesh_elem = geom_elem.firstChildElement()
                        if mesh_elem.tagName() == "mesh":
                            mesh_child_elem = mesh_elem.firstChildElement()
                            while not mesh_child_elem.isNull():
                                float_array_elem = mesh_child_elem.firstChildElement()
                                str_array = float_array_elem.firstChild().toText().data().split(" ")
                                if mesh_child_elem.attribute("id").endswith("-mesh-positions"):
                                    vert_pos_array = list(map(float, str_array))
                                if mesh_child_elem.attribute("id").endswith("-mesh-normals"):
                                    normal_array = list(map(float, str_array))
                                if mesh_child_elem.attribute("id").endswith("-mesh-map-0"):
                                    tex_coord_array = list(map(float, str_array))
                                if mesh_child_elem.tagName() == "triangles" or mesh_child_elem.tagName() == "polylist":
                                    p_child_elem = mesh_child_elem.firstChildElement()
                                    while not p_child_elem.isNull():
                                        if p_child_elem.tagName() == "p":
                                            str_indices = p_child_elem.firstChild().toText().data().split(" ")
                                            index_array = list(map(int, str_indices))
                                        p_child_elem = p_child_elem.nextSiblingElement()
                                mesh_child_elem = mesh_child_elem.nextSiblingElement()
                dae_elem = dae_elem.nextSiblingElement()
            # print(vert_pos_array)
            # print(normal_array)
            # print(tex_coord_array)
            # print(index_array)
            
            num_of_attributes = 3
            vert_positions = []
            normals = []
            tex_coords = []
            for i in range(0, len(index_array), num_of_attributes):
                vert_pos_index = index_array[i + 0]
                vert_positions.append(vert_pos_array[vert_pos_index * 3 + 0])
                vert_positions.append(vert_pos_array[vert_pos_index * 3 + 1])
                vert_positions.append(vert_pos_array[vert_pos_index * 3 + 2])
                
                normal_index = index_array[i + 1]
                normals.append(normal_array[normal_index * 3 + 0])
                normals.append(normal_array[normal_index * 3 + 1])
                normals.append(normal_array[normal_index * 3 + 2])
                
                tex_coord_index = index_array[i + 2]
                tex_coords.append(tex_coord_array[tex_coord_index * 2 + 0])
                tex_coords.append(tex_coord_array[tex_coord_index * 2 + 1])
            # print(vert_positions)
            # print(normals)
            # print(tex_coords)
            
            output = {}
     
            vert_positions = np.array(vert_positions, dtype=np.float32)
            vert_pos_buffer = QOpenGLBuffer()
            vert_pos_buffer.create()
            vert_pos_buffer.bind()
            vert_pos_buffer.allocate(vert_positions, len(vert_positions) * 4)
            
            normals = np.array(normals, dtype=np.float32)
            normal_buffer = QOpenGLBuffer()
            normal_buffer.create()
            normal_buffer.bind()
            normal_buffer.allocate(normals, len(normals) * 4)
            
            tex_coords = np.array(tex_coords, dtype=np.float32)
            tex_coord_buffer = QOpenGLBuffer()
            tex_coord_buffer.create()
            tex_coord_buffer.bind()
            tex_coord_buffer.allocate(tex_coords, len(tex_coords) * 4)
     
            vert_buffers = VertexBuffers()
            vert_buffers.vert_pos_buffer = vert_pos_buffer
            vert_buffers.normal_buffer = normal_buffer
            vert_buffers.tex_coord_buffer = tex_coord_buffer
            vert_buffers.amount_of_vertices = int(len(index_array) / 3);
            
            return vert_buffers
     
    def main():
        QApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
        app = QApplication(sys.argv)
        w = Window()
        w.show()
        sys.exit(app.exec_())
     
    if __name__ == "__main__":
        main()
  • PySide2: https://rextester.com/APZF83828
    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
    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
    
    import sys
    import numpy as np
    from OpenGL import GL as gl
    from PySide2.QtWidgets import QApplication, QOpenGLWidget
    from PySide2.QtGui import QOpenGLShaderProgram, QOpenGLShader, QOpenGLBuffer
    from PySide2.QtGui import QOpenGLTexture, QImage
    from PySide2.QtGui import QMatrix4x4, QVector3D
    from PySide2.QtXml import QDomDocument, QDomElement
    from PySide2.QtCore import Qt, QFile, QIODevice
     
    class VertexBuffers:
        vertex_pos_buffer = None
        normal_buffer = None
        tex_coord_buffer = None
        amount_of_vertices = None
     
    class Locations:
        mvp_matrix_location = None
        model_matrix_location = None
        normal_matrix_location = None
     
    class Object3D:
        position = QVector3D(0, 0, 0)
        rotation = QVector3D(0, 0, 0)
        scale = QVector3D(1, 1, 1)
        mvp_matrix = QMatrix4x4()
        model_matrix = QMatrix4x4()
        normal_matrix = QMatrix4x4()
     
        def __init__(self, vert_buffers, locations, texture):
            self.vert_pos_buffer = vert_buffers.vert_pos_buffer
            self.normal_buffer = vert_buffers.normal_buffer
            self.tex_coord_buffer = vert_buffers.tex_coord_buffer
            self.amount_of_vertices = vert_buffers.amount_of_vertices
            
            self.mvp_matrix_location = locations.mvp_matrix_location
            self.model_matrix_location = locations.model_matrix_location
            self.normal_matrix_location = locations.normal_matrix_location
            
            self.texture = texture
     
        def draw(self, program, proj_view_matrix):
            program.bind()
     
            self.vert_pos_buffer.bind()
            program.setAttributeBuffer(0, gl.GL_FLOAT, 0, 3)
            program.enableAttributeArray(0)
     
            self.normal_buffer.bind()
            program.setAttributeBuffer(1, gl.GL_FLOAT, 0, 3)
            program.enableAttributeArray(1)
     
            self.tex_coord_buffer.bind()
            program.setAttributeBuffer(2, gl.GL_FLOAT, 0, 2)
            program.enableAttributeArray(2)
            
            self.model_matrix.setToIdentity()
            self.model_matrix.translate(self.position)
            self.model_matrix.rotate(self.rotation.x(), QVector3D(1, 0, 0))
            self.model_matrix.rotate(self.rotation.y(), QVector3D(0, 1, 0))
            self.model_matrix.rotate(self.rotation.z(), QVector3D(0, 0, 1))
            self.model_matrix.scale(self.scale)
            self.mvp_matrix = proj_view_matrix * self.model_matrix;
            
            self.normal_matrix = self.model_matrix.inverted()
            self.normal_matrix = self.normal_matrix[0].transposed()
            
            program.bind()
            program.setUniformValue(self.mvp_matrix_location, self.mvp_matrix)
            program.setUniformValue(self.model_matrix_location, self.model_matrix)
            program.setUniformValue(self.normal_matrix_location, self.normal_matrix)
            
            self.texture.bind()
     
            gl.glDrawArrays(gl.GL_TRIANGLES, 0, self.amount_of_vertices)
     
    class Window(QOpenGLWidget):
     
        def __init__(self):
            super().__init__()
            self.setWindowTitle("Dae, Collada")
            self.resize(268, 268)
     
        def initializeGL(self):
            gl.glClearColor(0.2, 0.2, 0.2, 1)
            gl.glEnable(gl.GL_DEPTH_TEST)
            vertShaderSrc = """
                #version 330 core
     
                in vec4 aPosition;
                in vec4 aNormal;
                in vec2 aTexCoord;
     
                uniform mat4 uMvpMatrix;
                uniform mat4 uModelMatrix;
                uniform mat4 uNormalMatrix;
     
                out vec3 vPosition;
                out vec3 vNormal;
                out vec2 vTexCoord;
     
                void main()
                {
                    gl_Position = uMvpMatrix * aPosition;
                    vPosition = vec3(uModelMatrix * aPosition);
                    vNormal = normalize(vec3(uNormalMatrix * aNormal));
                    vTexCoord = aTexCoord;
                }
            """
            fragShaderSrc = """
                #version 330 core
     
                const vec3 lightColor = vec3(0.8, 0.8, 0.8);
                const vec3 lightPosition = vec3(5.0, 7.0, 2.0);
                const vec3 ambientLight = vec3(0.3, 0.3, 0.3);
     
                uniform sampler2D uSampler;
     
                in vec3 vPosition;
                in vec3 vNormal;
                in vec2 vTexCoord;
     
                void main()
                {
                    vec4 color = texture2D(uSampler, vTexCoord);
                    vec3 normal = normalize(vNormal);
                    vec3 lightDirection = normalize(lightPosition - vPosition);
                    float nDotL = max(dot(lightDirection, normal), 0.0);
                    vec3 diffuse = lightColor * color.rgb * nDotL;
                    vec3 ambient = ambientLight * color.rgb;
                    gl_FragColor = vec4(diffuse + ambient, color.a);
                }
            """
            self.program = QOpenGLShaderProgram()
            self.program.addShaderFromSourceCode(QOpenGLShader.Vertex, vertShaderSrc)
            self.program.addShaderFromSourceCode(QOpenGLShader.Fragment, fragShaderSrc)
            self.program.link()
            self.program.bind()
            self.program.bindAttributeLocation("aPosition", 0)
            self.program.bindAttributeLocation("aNormal", 1)
            self.program.bindAttributeLocation("aTexCoord", 2)
            locations = Locations()
            self.program.bind()
            locations.mvp_matrix_location = self.program.uniformLocation("uMvpMatrix");
            locations.model_matrix_location = self.program.uniformLocation("uModelMatrix")
            locations.normal_matrix_location = self.program.uniformLocation("uNormalMatrix")
            self.vert_buffers = self.initVertexBuffers("assets/cube.dae")
            self.proj_view_matrix = QMatrix4x4()
            self.proj_matrix = QMatrix4x4()
            self.view_matrix = QMatrix4x4()
            self.view_matrix.lookAt(
                QVector3D(2, 3, 5),
                QVector3D(0, 0, 0),
                QVector3D(0, 1, 0))
            
            self.texture = QOpenGLTexture(QOpenGLTexture.Target2D)
            self.texture.create()
            self.texture.setData(QImage("assets/cube.png"))
            self.texture.setMinMagFilters(QOpenGLTexture.Linear, QOpenGLTexture.Linear)
            self.texture.setWrapMode(QOpenGLTexture.ClampToEdge)
            self.plane = Object3D(self.vert_buffers, locations, self.texture)
            
        def paintGL(self):
            gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
            self.proj_view_matrix = self.proj_matrix * self.view_matrix
            self.plane.draw(self.program, self.proj_view_matrix)
     
        def resizeGL(self, w, h):
            gl.glViewport(0, 0, w, h)
            self.proj_matrix.setToIdentity()
            self.proj_matrix.perspective(50, float(w) / float(h), 0.1, 100)
            
        def initVertexBuffers(self, path):
            xml_doc = QDomDocument()
            file = QFile(path)
            if not file.open(QIODevice.ReadOnly):
                print("Failed to open the file: " + path)
            xml_doc.setContent(file)
            file.close()
            
            vert_pos_array = []
            normal_array = []
            tex_coord_array = []
            index_array = []
            
            root = xml_doc.documentElement()
            dae_elem = root.firstChildElement()
            while not dae_elem.isNull():
                if dae_elem.tagName() == "library_geometries":
                    geom_elem = dae_elem.firstChildElement()
                    if geom_elem.tagName() == "geometry":
                        mesh_elem = geom_elem.firstChildElement()
                        if mesh_elem.tagName() == "mesh":
                            mesh_child_elem = mesh_elem.firstChildElement()
                            while not mesh_child_elem.isNull():
                                float_array_elem = mesh_child_elem.firstChildElement()
                                str_array = float_array_elem.firstChild().toText().data().split(" ")
                                if mesh_child_elem.attribute("id").endswith("-mesh-positions"):
                                    vert_pos_array = list(map(float, str_array))
                                if mesh_child_elem.attribute("id").endswith("-mesh-normals"):
                                    normal_array = list(map(float, str_array))
                                if mesh_child_elem.attribute("id").endswith("-mesh-map-0"):
                                    tex_coord_array = list(map(float, str_array))
                                if mesh_child_elem.tagName() == "triangles" or mesh_child_elem.tagName() == "polylist":
                                    p_child_elem = mesh_child_elem.firstChildElement()
                                    while not p_child_elem.isNull():
                                        if p_child_elem.tagName() == "p":
                                            str_indices = p_child_elem.firstChild().toText().data().split(" ")
                                            index_array = list(map(int, str_indices))
                                        p_child_elem = p_child_elem.nextSiblingElement()
                                mesh_child_elem = mesh_child_elem.nextSiblingElement()
                dae_elem = dae_elem.nextSiblingElement()
            # print(vert_pos_array)
            # print(normal_array)
            # print(tex_coord_array)
            # print(index_array)
            
            num_of_attributes = 3
            vert_positions = []
            normals = []
            tex_coords = []
            for i in range(0, len(index_array), num_of_attributes):
                vert_pos_index = index_array[i + 0]
                vert_positions.append(vert_pos_array[vert_pos_index * 3 + 0])
                vert_positions.append(vert_pos_array[vert_pos_index * 3 + 1])
                vert_positions.append(vert_pos_array[vert_pos_index * 3 + 2])
                
                normal_index = index_array[i + 1]
                normals.append(normal_array[normal_index * 3 + 0])
                normals.append(normal_array[normal_index * 3 + 1])
                normals.append(normal_array[normal_index * 3 + 2])
                
                tex_coord_index = index_array[i + 2]
                tex_coords.append(tex_coord_array[tex_coord_index * 2 + 0])
                tex_coords.append(tex_coord_array[tex_coord_index * 2 + 1])
            # print(vert_positions)
            # print(normals)
            # print(tex_coords)
            
            output = {}
     
            vert_positions = np.array(vert_positions, dtype=np.float32)
            vert_pos_buffer = QOpenGLBuffer()
            vert_pos_buffer.create()
            vert_pos_buffer.bind()
            vert_pos_buffer.allocate(vert_positions, len(vert_positions) * 4)
            
            normals = np.array(normals, dtype=np.float32)
            normal_buffer = QOpenGLBuffer()
            normal_buffer.create()
            normal_buffer.bind()
            normal_buffer.allocate(normals, len(normals) * 4)
            
            tex_coords = np.array(tex_coords, dtype=np.float32)
            tex_coord_buffer = QOpenGLBuffer()
            tex_coord_buffer.create()
            tex_coord_buffer.bind()
            tex_coord_buffer.allocate(tex_coords, len(tex_coords) * 4)
     
            vert_buffers = VertexBuffers()
            vert_buffers.vert_pos_buffer = vert_pos_buffer
            vert_buffers.normal_buffer = normal_buffer
            vert_buffers.tex_coord_buffer = tex_coord_buffer
            vert_buffers.amount_of_vertices = int(len(index_array) / 3);
            
            return vert_buffers
     
    def main():
        QApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
        app = QApplication(sys.argv)
        w = Window()
        w.show()
        sys.exit(app.exec_())
     
    if __name__ == "__main__":
        main()
Вложения
Тип файла: rar load_texture_object_from_dae_pyqt5.rar (145.8 Кб, 6 просмотров)
Тип файла: rar load_texture_object_from_dae_pyside2.rar (145.8 Кб, 0 просмотров)
3
9933 / 2936 / 494
Регистрация: 05.10.2013
Сообщений: 7,966
Записей в блоге: 217
25.01.2021, 14:39
Лучший ответ Сообщение было отмечено u235 как решение

Решение

Анимация движения вверх-вниз 3D-модели загруженной из Blender из формата .dae (COLLADA)

Название: move_dae_obj_up_and_down.gif
Просмотров: 135

Размер: 191.5 Кб
Вложения
Тип файла: zip move_dae_obj_up_and_down_pyqt5.zip (146.6 Кб, 9 просмотров)
Тип файла: zip move_dae_obj_up_and_down_pyside2.zip (146.7 Кб, 6 просмотров)
3
3 / 3 / 0
Регистрация: 04.11.2018
Сообщений: 123
30.01.2021, 19:09  [ТС]
8Observer8, Спасибо огроменное, вы мне очень помогли)))
1
9933 / 2936 / 494
Регистрация: 05.10.2013
Сообщений: 7,966
Записей в блоге: 217
16.03.2021, 18:30
Добавил в данный пример физику с помощью библиотеки Bullet. Так как я не смог разобраться, как связать PyBullet (стандартный порт C++ библиотеки Bullet) c OpenGL, то я взял порт Bullet из движка Panda3D, который идёт без привязки к графике Panda3D и может использоваться отдельно со своими рендером на OpenGL. Выложу пример здесь. Может кому-то нужно будет использовать симуляцию физики. Кубик падает на кубик и после удара начинает вращаться.
  • PyQt5, OpenGL 3.3: https://rextester.com/MKV35748
    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
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    
    import sys
    import numpy as np
    from OpenGL import GL as gl
    from PyQt5.QtWidgets import QApplication, QOpenGLWidget
    from PyQt5.QtGui import QOpenGLShaderProgram, QOpenGLShader, QOpenGLBuffer
    from PyQt5.QtGui import QOpenGLTexture, QImage
    from PyQt5.QtGui import QMatrix4x4, QVector3D, QQuaternion
    from PyQt5.QtXml import QDomDocument, QDomElement
    from PyQt5.QtCore import Qt, QFile, QIODevice
    from PyQt5.QtCore import QTimer, QElapsedTimer
     
    from panda3d.bullet import BulletWorld
    from panda3d.core import TransformState, Vec3, Quat, Point3
    from panda3d.bullet import BulletBoxShape
    from panda3d.bullet import BulletRigidBodyNode
     
    # Assets:
    # Cube Texture: https://dl.dropboxusercontent.com/s/tply9ubx3n3ycvv/cube.png
    # Cube Model: https://dl.dropboxusercontent.com/s/0aktc37c3nx9iq3/cube.dae
    # Plane Texture: https://dl.dropboxusercontent.com/s/3iibsnvyw0vupby/plane.png
    # Plane Model: https://dl.dropboxusercontent.com/s/e0wktg69ec3w8pq/plane.dae
     
    class VertexBuffers:
        vertex_pos_buffer = None
        normal_buffer = None
        tex_coord_buffer = None
        amount_of_vertices = None
     
    class Locations:
        mvp_matrix_location = None
        model_matrix_location = None
        normal_matrix_location = None
     
    class Object3D:
        position = QVector3D(0, 0, 0)
        rotation = QVector3D(0, 0, 0)
        scale = QVector3D(1, 1, 1)
        mvp_matrix = QMatrix4x4()
        model_matrix = QMatrix4x4()
        normal_matrix = QMatrix4x4()
     
        def __init__(self, vert_buffers, locations, texture, world, mass, pos):
            self.vert_pos_buffer = vert_buffers.vert_pos_buffer
            self.normal_buffer = vert_buffers.normal_buffer
            self.tex_coord_buffer = vert_buffers.tex_coord_buffer
            self.amount_of_vertices = vert_buffers.amount_of_vertices
            
            self.mvp_matrix_location = locations.mvp_matrix_location
            self.model_matrix_location = locations.model_matrix_location
            self.normal_matrix_location = locations.normal_matrix_location
            
            self.texture = texture
     
            self.shape = BulletBoxShape(Vec3(0.5, 0.5, 0.5))
            self.node = BulletRigidBodyNode('Box')
     
            self.position = pos
            self.mass = mass
            self.node.setMass(self.mass)
     
            p = Point3(self.position.x(), self.position.y(), self.position.z())
            q = Quat.identQuat()
            s = Vec3(1, 1, 1)
     
            self.transform = TransformState.make_pos_quat_scale(p, q, s)
            self.node.setTransform(self.transform)
     
            self.node.addShape(self.shape)
            self.world = world
            self.world.attachRigidBody(self.node)
     
        def draw(self, program, proj_view_matrix):
            program.bind()
     
            self.vert_pos_buffer.bind()
            program.setAttributeBuffer(0, gl.GL_FLOAT, 0, 3)
            program.enableAttributeArray(0)
     
            self.normal_buffer.bind()
            program.setAttributeBuffer(1, gl.GL_FLOAT, 0, 3)
            program.enableAttributeArray(1)
     
            self.tex_coord_buffer.bind()
            program.setAttributeBuffer(2, gl.GL_FLOAT, 0, 2)
            program.enableAttributeArray(2)
     
            self.position.setX(self.node.getTransform().pos.x)
            self.position.setY(self.node.getTransform().pos.y)
            self.position.setZ(self.node.getTransform().pos.z)
            hpr = self.node.getTransform().getHpr()
            pandaQuat = Quat()
            pandaQuat.setHpr(hpr)
            quat = QQuaternion(pandaQuat.getX(), pandaQuat.getY(), pandaQuat.getZ(), pandaQuat.getW())
            
            self.model_matrix.setToIdentity()
            self.model_matrix.translate(self.position)
            self.model_matrix.rotate(quat)
            self.model_matrix.scale(self.scale)
            self.mvp_matrix = proj_view_matrix * self.model_matrix
            
            self.normal_matrix = self.model_matrix.inverted()
            self.normal_matrix = self.normal_matrix[0].transposed()
            
            program.bind()
            program.setUniformValue(self.mvp_matrix_location, self.mvp_matrix)
            program.setUniformValue(self.model_matrix_location, self.model_matrix)
            program.setUniformValue(self.normal_matrix_location, self.normal_matrix)
            
            self.texture.bind()
     
            gl.glDrawArrays(gl.GL_TRIANGLES, 0, self.amount_of_vertices)
     
    class Window(QOpenGLWidget):
     
        def __init__(self):
            super().__init__()
            self.setWindowTitle("Bullet Physics")
            self.resize(268, 268)
     
        def initializeGL(self):
            gl.glClearColor(0.2, 0.2, 0.2, 1)
            gl.glEnable(gl.GL_DEPTH_TEST)
            vertShaderSrc = """
                #version 330 core
     
                in vec4 aPosition;
                in vec4 aNormal;
                in vec2 aTexCoord;
     
                uniform mat4 uMvpMatrix;
                uniform mat4 uModelMatrix;
                uniform mat4 uNormalMatrix;
     
                out vec3 vPosition;
                out vec3 vNormal;
                out vec2 vTexCoord;
     
                void main()
                {
                    gl_Position = uMvpMatrix * aPosition;
                    vPosition = vec3(uModelMatrix * aPosition);
                    vNormal = normalize(vec3(uNormalMatrix * aNormal));
                    vTexCoord = aTexCoord;
                }
            """
            fragShaderSrc = """
                #version 330 core
     
                const vec3 lightColor = vec3(0.8, 0.8, 0.8);
                const vec3 lightPosition = vec3(5.0, 7.0, 2.0);
                const vec3 ambientLight = vec3(0.3, 0.3, 0.3);
     
                uniform sampler2D uSampler;
     
                in vec3 vPosition;
                in vec3 vNormal;
                in vec2 vTexCoord;
     
                void main()
                {
                    vec4 color = texture2D(uSampler, vTexCoord);
                    vec3 normal = normalize(vNormal);
                    vec3 lightDirection = normalize(lightPosition - vPosition);
                    float nDotL = max(dot(lightDirection, normal), 0.0);
                    vec3 diffuse = lightColor * color.rgb * nDotL;
                    vec3 ambient = ambientLight * color.rgb;
                    gl_FragColor = vec4(diffuse + ambient, color.a);
                }
            """
            self.program = QOpenGLShaderProgram()
            self.program.addShaderFromSourceCode(QOpenGLShader.Vertex, vertShaderSrc)
            self.program.addShaderFromSourceCode(QOpenGLShader.Fragment, fragShaderSrc)
            self.program.link()
            self.program.bind()
            self.program.bindAttributeLocation("aPosition", 0)
            self.program.bindAttributeLocation("aNormal", 1)
            self.program.bindAttributeLocation("aTexCoord", 2)
            locations = Locations()
            self.program.bind()
            locations.mvp_matrix_location = self.program.uniformLocation("uMvpMatrix")
            locations.model_matrix_location = self.program.uniformLocation("uModelMatrix")
            locations.normal_matrix_location = self.program.uniformLocation("uNormalMatrix")
            self.vert_buffers = self.initVertexBuffers("assets/cube.dae")
            self.proj_view_matrix = QMatrix4x4()
            self.proj_matrix = QMatrix4x4()
            self.view_matrix = QMatrix4x4()
            self.view_matrix.lookAt(
                QVector3D(2, 3, 5),
                QVector3D(0, 0, 0),
                QVector3D(0, 1, 0))
            
            self.texture = QOpenGLTexture(QOpenGLTexture.Target2D)
            self.texture.create()
            self.texture.setData(QImage("assets/cube.png"))
            self.texture.setMinMagFilters(QOpenGLTexture.Linear, QOpenGLTexture.Linear)
            self.texture.setWrapMode(QOpenGLTexture.ClampToEdge)
     
            self.world = BulletWorld()
            self.world.setGravity(Vec3(0, -9.81, 0))
     
            self.obj = Object3D(self.vert_buffers, locations, self.texture, self.world, mass=0, pos=QVector3D(0, -3, 0))
            self.obj2 = Object3D(self.vert_buffers, locations, self.texture, self.world, mass=1, pos=QVector3D(0.8, 3, 0))
            
            #self.move_dir = 1 # move direction: 1 - up, -1 - down
            #self.move_speed = 0.002
            
            self.timer = QTimer()
            self.timer.timeout.connect(self.animationLoop)
            self.elapsed_timer = QElapsedTimer()
            self.elapsed_timer.start()
            self.delta_time = 0
            self.timer.start(1000/60)
            
        def animationLoop(self):
            self.delta_time = self.elapsed_timer.elapsed()
            self.elapsed_timer.restart()
            self.world.doPhysics(self.delta_time / 1000)
            self.update()
            
        def paintGL(self):
            gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
            self.proj_view_matrix = self.proj_matrix * self.view_matrix
            self.obj.draw(self.program, self.proj_view_matrix)
            self.obj2.draw(self.program, self.proj_view_matrix)
     
        def resizeGL(self, w, h):
            gl.glViewport(0, 0, w, h)
            self.proj_matrix.setToIdentity()
            self.proj_matrix.perspective(50, float(w) / float(h), 0.1, 100)
            
        def initVertexBuffers(self, path):
            xml_doc = QDomDocument()
            file = QFile(path)
            if not file.open(QIODevice.ReadOnly):
                print("Failed to open the file: " + path)
            xml_doc.setContent(file)
            file.close()
            
            vert_pos_array = []
            normal_array = []
            tex_coord_array = []
            index_array = []
            
            root = xml_doc.documentElement()
            dae_elem = root.firstChildElement()
            while not dae_elem.isNull():
                if dae_elem.tagName() == "library_geometries":
                    geom_elem = dae_elem.firstChildElement()
                    if geom_elem.tagName() == "geometry":
                        mesh_elem = geom_elem.firstChildElement()
                        if mesh_elem.tagName() == "mesh":
                            mesh_child_elem = mesh_elem.firstChildElement()
                            while not mesh_child_elem.isNull():
                                float_array_elem = mesh_child_elem.firstChildElement()
                                str_array = float_array_elem.firstChild().toText().data().split(" ")
                                if mesh_child_elem.attribute("id").endswith("-mesh-positions"):
                                    vert_pos_array = list(map(float, str_array))
                                if mesh_child_elem.attribute("id").endswith("-mesh-normals"):
                                    normal_array = list(map(float, str_array))
                                if mesh_child_elem.attribute("id").endswith("-mesh-map-0"):
                                    tex_coord_array = list(map(float, str_array))
                                if mesh_child_elem.tagName() == "triangles" or mesh_child_elem.tagName() == "polylist":
                                    p_child_elem = mesh_child_elem.firstChildElement()
                                    while not p_child_elem.isNull():
                                        if p_child_elem.tagName() == "p":
                                            str_indices = p_child_elem.firstChild().toText().data().split(" ")
                                            index_array = list(map(int, str_indices))
                                        p_child_elem = p_child_elem.nextSiblingElement()
                                mesh_child_elem = mesh_child_elem.nextSiblingElement()
                dae_elem = dae_elem.nextSiblingElement()
            # print(vert_pos_array)
            # print(normal_array)
            # print(tex_coord_array)
            # print(index_array)
            
            num_of_attributes = 3
            vert_positions = []
            normals = []
            tex_coords = []
            for i in range(0, len(index_array), num_of_attributes):
                vert_pos_index = index_array[i + 0]
                vert_positions.append(vert_pos_array[vert_pos_index * 3 + 0])
                vert_positions.append(vert_pos_array[vert_pos_index * 3 + 1])
                vert_positions.append(vert_pos_array[vert_pos_index * 3 + 2])
                
                normal_index = index_array[i + 1]
                normals.append(normal_array[normal_index * 3 + 0])
                normals.append(normal_array[normal_index * 3 + 1])
                normals.append(normal_array[normal_index * 3 + 2])
                
                tex_coord_index = index_array[i + 2]
                tex_coords.append(tex_coord_array[tex_coord_index * 2 + 0])
                tex_coords.append(tex_coord_array[tex_coord_index * 2 + 1])
            # print(vert_positions)
            # print(normals)
            # print(tex_coords)
            
            output = {}
     
            vert_positions = np.array(vert_positions, dtype=np.float32)
            vert_pos_buffer = QOpenGLBuffer()
            vert_pos_buffer.create()
            vert_pos_buffer.bind()
            vert_pos_buffer.allocate(vert_positions, len(vert_positions) * 4)
            
            normals = np.array(normals, dtype=np.float32)
            normal_buffer = QOpenGLBuffer()
            normal_buffer.create()
            normal_buffer.bind()
            normal_buffer.allocate(normals, len(normals) * 4)
            
            tex_coords = np.array(tex_coords, dtype=np.float32)
            tex_coord_buffer = QOpenGLBuffer()
            tex_coord_buffer.create()
            tex_coord_buffer.bind()
            tex_coord_buffer.allocate(tex_coords, len(tex_coords) * 4)
     
            vert_buffers = VertexBuffers()
            vert_buffers.vert_pos_buffer = vert_pos_buffer
            vert_buffers.normal_buffer = normal_buffer
            vert_buffers.tex_coord_buffer = tex_coord_buffer
            vert_buffers.amount_of_vertices = int(len(index_array) / 3)
            
            return vert_buffers
     
    def main():
        QApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
        app = QApplication(sys.argv)
        w = Window()
        w.show()
        sys.exit(app.exec_())
     
    if __name__ == "__main__":
        main()
1
9933 / 2936 / 494
Регистрация: 05.10.2013
Сообщений: 7,966
Записей в блоге: 217
16.03.2021, 18:31
  • PySide2, OpenGL 3.3: https://rextester.com/RAHNB58294
    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
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    
    import sys
    import numpy as np
    from OpenGL import GL as gl
    from PySide2.QtWidgets import QApplication, QOpenGLWidget
    from PySide2.QtGui import QOpenGLShaderProgram, QOpenGLShader, QOpenGLBuffer
    from PySide2.QtGui import QOpenGLTexture, QImage
    from PySide2.QtGui import QMatrix4x4, QVector3D, QQuaternion
    from PySide2.QtXml import QDomDocument, QDomElement
    from PySide2.QtCore import Qt, QFile, QIODevice
    from PySide2.QtCore import QTimer, QElapsedTimer
     
    from panda3d.bullet import BulletWorld
    from panda3d.core import TransformState, Vec3, Quat, Point3
    from panda3d.bullet import BulletBoxShape
    from panda3d.bullet import BulletRigidBodyNode
     
    # Assets:
    # Cube Texture: https://dl.dropboxusercontent.com/s/tply9ubx3n3ycvv/cube.png
    # Cube Model: https://dl.dropboxusercontent.com/s/0aktc37c3nx9iq3/cube.dae
    # Plane Texture: https://dl.dropboxusercontent.com/s/3iibsnvyw0vupby/plane.png
    # Plane Model: https://dl.dropboxusercontent.com/s/e0wktg69ec3w8pq/plane.dae
     
    class VertexBuffers:
        vertex_pos_buffer = None
        normal_buffer = None
        tex_coord_buffer = None
        amount_of_vertices = None
     
    class Locations:
        mvp_matrix_location = None
        model_matrix_location = None
        normal_matrix_location = None
     
    class Object3D:
        position = QVector3D(0, 0, 0)
        rotation = QVector3D(0, 0, 0)
        scale = QVector3D(1, 1, 1)
        mvp_matrix = QMatrix4x4()
        model_matrix = QMatrix4x4()
        normal_matrix = QMatrix4x4()
     
        def __init__(self, vert_buffers, locations, texture, world, mass, pos):
            self.vert_pos_buffer = vert_buffers.vert_pos_buffer
            self.normal_buffer = vert_buffers.normal_buffer
            self.tex_coord_buffer = vert_buffers.tex_coord_buffer
            self.amount_of_vertices = vert_buffers.amount_of_vertices
            
            self.mvp_matrix_location = locations.mvp_matrix_location
            self.model_matrix_location = locations.model_matrix_location
            self.normal_matrix_location = locations.normal_matrix_location
            
            self.texture = texture
     
            self.shape = BulletBoxShape(Vec3(0.5, 0.5, 0.5))
            self.node = BulletRigidBodyNode('Box')
     
            self.position = pos
            self.mass = mass
            self.node.setMass(self.mass)
     
            p = Point3(self.position.x(), self.position.y(), self.position.z())
            q = Quat.identQuat()
            s = Vec3(1, 1, 1)
     
            self.transform = TransformState.make_pos_quat_scale(p, q, s)
            self.node.setTransform(self.transform)
     
            self.node.addShape(self.shape)
            self.world = world
            self.world.attachRigidBody(self.node)
     
        def draw(self, program, proj_view_matrix):
            program.bind()
     
            self.vert_pos_buffer.bind()
            program.setAttributeBuffer(0, gl.GL_FLOAT, 0, 3)
            program.enableAttributeArray(0)
     
            self.normal_buffer.bind()
            program.setAttributeBuffer(1, gl.GL_FLOAT, 0, 3)
            program.enableAttributeArray(1)
     
            self.tex_coord_buffer.bind()
            program.setAttributeBuffer(2, gl.GL_FLOAT, 0, 2)
            program.enableAttributeArray(2)
     
            self.position.setX(self.node.getTransform().pos.x)
            self.position.setY(self.node.getTransform().pos.y)
            self.position.setZ(self.node.getTransform().pos.z)
            hpr = self.node.getTransform().getHpr()
            pandaQuat = Quat()
            pandaQuat.setHpr(hpr)
            quat = QQuaternion(pandaQuat.getX(), pandaQuat.getY(), pandaQuat.getZ(), pandaQuat.getW())
            
            self.model_matrix.setToIdentity()
            self.model_matrix.translate(self.position)
            self.model_matrix.rotate(quat)
            self.model_matrix.scale(self.scale)
            self.mvp_matrix = proj_view_matrix * self.model_matrix
            
            self.normal_matrix = self.model_matrix.inverted()
            self.normal_matrix = self.normal_matrix[0].transposed()
            
            program.bind()
            program.setUniformValue(self.mvp_matrix_location, self.mvp_matrix)
            program.setUniformValue(self.model_matrix_location, self.model_matrix)
            program.setUniformValue(self.normal_matrix_location, self.normal_matrix)
            
            self.texture.bind()
     
            gl.glDrawArrays(gl.GL_TRIANGLES, 0, self.amount_of_vertices)
     
    class Window(QOpenGLWidget):
     
        def __init__(self):
            super().__init__()
            self.setWindowTitle("Bullet Physics")
            self.resize(268, 268)
     
        def initializeGL(self):
            gl.glClearColor(0.2, 0.2, 0.2, 1)
            gl.glEnable(gl.GL_DEPTH_TEST)
            vertShaderSrc = """
                #version 330 core
     
                in vec4 aPosition;
                in vec4 aNormal;
                in vec2 aTexCoord;
     
                uniform mat4 uMvpMatrix;
                uniform mat4 uModelMatrix;
                uniform mat4 uNormalMatrix;
     
                out vec3 vPosition;
                out vec3 vNormal;
                out vec2 vTexCoord;
     
                void main()
                {
                    gl_Position = uMvpMatrix * aPosition;
                    vPosition = vec3(uModelMatrix * aPosition);
                    vNormal = normalize(vec3(uNormalMatrix * aNormal));
                    vTexCoord = aTexCoord;
                }
            """
            fragShaderSrc = """
                #version 330 core
     
                const vec3 lightColor = vec3(0.8, 0.8, 0.8);
                const vec3 lightPosition = vec3(5.0, 7.0, 2.0);
                const vec3 ambientLight = vec3(0.3, 0.3, 0.3);
     
                uniform sampler2D uSampler;
     
                in vec3 vPosition;
                in vec3 vNormal;
                in vec2 vTexCoord;
     
                void main()
                {
                    vec4 color = texture2D(uSampler, vTexCoord);
                    vec3 normal = normalize(vNormal);
                    vec3 lightDirection = normalize(lightPosition - vPosition);
                    float nDotL = max(dot(lightDirection, normal), 0.0);
                    vec3 diffuse = lightColor * color.rgb * nDotL;
                    vec3 ambient = ambientLight * color.rgb;
                    gl_FragColor = vec4(diffuse + ambient, color.a);
                }
            """
            self.program = QOpenGLShaderProgram()
            self.program.addShaderFromSourceCode(QOpenGLShader.Vertex, vertShaderSrc)
            self.program.addShaderFromSourceCode(QOpenGLShader.Fragment, fragShaderSrc)
            self.program.link()
            self.program.bind()
            self.program.bindAttributeLocation("aPosition", 0)
            self.program.bindAttributeLocation("aNormal", 1)
            self.program.bindAttributeLocation("aTexCoord", 2)
            locations = Locations()
            self.program.bind()
            locations.mvp_matrix_location = self.program.uniformLocation("uMvpMatrix")
            locations.model_matrix_location = self.program.uniformLocation("uModelMatrix")
            locations.normal_matrix_location = self.program.uniformLocation("uNormalMatrix")
            self.vert_buffers = self.initVertexBuffers("assets/cube.dae")
            self.proj_view_matrix = QMatrix4x4()
            self.proj_matrix = QMatrix4x4()
            self.view_matrix = QMatrix4x4()
            self.view_matrix.lookAt(
                QVector3D(2, 3, 5),
                QVector3D(0, 0, 0),
                QVector3D(0, 1, 0))
            
            self.texture = QOpenGLTexture(QOpenGLTexture.Target2D)
            self.texture.create()
            self.texture.setData(QImage("assets/cube.png"))
            self.texture.setMinMagFilters(QOpenGLTexture.Linear, QOpenGLTexture.Linear)
            self.texture.setWrapMode(QOpenGLTexture.ClampToEdge)
     
            self.world = BulletWorld()
            self.world.setGravity(Vec3(0, -9.81, 0))
     
            self.obj = Object3D(self.vert_buffers, locations, self.texture, self.world, mass=0, pos=QVector3D(0, -3, 0))
            self.obj2 = Object3D(self.vert_buffers, locations, self.texture, self.world, mass=1, pos=QVector3D(0.8, 3, 0))
            
            #self.move_dir = 1 # move direction: 1 - up, -1 - down
            #self.move_speed = 0.002
            
            self.timer = QTimer()
            self.timer.timeout.connect(self.animationLoop)
            self.elapsed_timer = QElapsedTimer()
            self.elapsed_timer.start()
            self.delta_time = 0
            self.timer.start(1000/60)
            
        def animationLoop(self):
            self.delta_time = self.elapsed_timer.elapsed()
            self.elapsed_timer.restart()
            self.world.doPhysics(self.delta_time / 1000)
            self.update()
            
        def paintGL(self):
            gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
            self.proj_view_matrix = self.proj_matrix * self.view_matrix
            self.obj.draw(self.program, self.proj_view_matrix)
            self.obj2.draw(self.program, self.proj_view_matrix)
     
        def resizeGL(self, w, h):
            gl.glViewport(0, 0, w, h)
            self.proj_matrix.setToIdentity()
            self.proj_matrix.perspective(50, float(w) / float(h), 0.1, 100)
            
        def initVertexBuffers(self, path):
            xml_doc = QDomDocument()
            file = QFile(path)
            if not file.open(QIODevice.ReadOnly):
                print("Failed to open the file: " + path)
            xml_doc.setContent(file)
            file.close()
            
            vert_pos_array = []
            normal_array = []
            tex_coord_array = []
            index_array = []
            
            root = xml_doc.documentElement()
            dae_elem = root.firstChildElement()
            while not dae_elem.isNull():
                if dae_elem.tagName() == "library_geometries":
                    geom_elem = dae_elem.firstChildElement()
                    if geom_elem.tagName() == "geometry":
                        mesh_elem = geom_elem.firstChildElement()
                        if mesh_elem.tagName() == "mesh":
                            mesh_child_elem = mesh_elem.firstChildElement()
                            while not mesh_child_elem.isNull():
                                float_array_elem = mesh_child_elem.firstChildElement()
                                str_array = float_array_elem.firstChild().toText().data().split(" ")
                                if mesh_child_elem.attribute("id").endswith("-mesh-positions"):
                                    vert_pos_array = list(map(float, str_array))
                                if mesh_child_elem.attribute("id").endswith("-mesh-normals"):
                                    normal_array = list(map(float, str_array))
                                if mesh_child_elem.attribute("id").endswith("-mesh-map-0"):
                                    tex_coord_array = list(map(float, str_array))
                                if mesh_child_elem.tagName() == "triangles" or mesh_child_elem.tagName() == "polylist":
                                    p_child_elem = mesh_child_elem.firstChildElement()
                                    while not p_child_elem.isNull():
                                        if p_child_elem.tagName() == "p":
                                            str_indices = p_child_elem.firstChild().toText().data().split(" ")
                                            index_array = list(map(int, str_indices))
                                        p_child_elem = p_child_elem.nextSiblingElement()
                                mesh_child_elem = mesh_child_elem.nextSiblingElement()
                dae_elem = dae_elem.nextSiblingElement()
            # print(vert_pos_array)
            # print(normal_array)
            # print(tex_coord_array)
            # print(index_array)
            
            num_of_attributes = 3
            vert_positions = []
            normals = []
            tex_coords = []
            for i in range(0, len(index_array), num_of_attributes):
                vert_pos_index = index_array[i + 0]
                vert_positions.append(vert_pos_array[vert_pos_index * 3 + 0])
                vert_positions.append(vert_pos_array[vert_pos_index * 3 + 1])
                vert_positions.append(vert_pos_array[vert_pos_index * 3 + 2])
                
                normal_index = index_array[i + 1]
                normals.append(normal_array[normal_index * 3 + 0])
                normals.append(normal_array[normal_index * 3 + 1])
                normals.append(normal_array[normal_index * 3 + 2])
                
                tex_coord_index = index_array[i + 2]
                tex_coords.append(tex_coord_array[tex_coord_index * 2 + 0])
                tex_coords.append(tex_coord_array[tex_coord_index * 2 + 1])
            # print(vert_positions)
            # print(normals)
            # print(tex_coords)
            
            output = {}
     
            vert_positions = np.array(vert_positions, dtype=np.float32)
            vert_pos_buffer = QOpenGLBuffer()
            vert_pos_buffer.create()
            vert_pos_buffer.bind()
            vert_pos_buffer.allocate(vert_positions, len(vert_positions) * 4)
            
            normals = np.array(normals, dtype=np.float32)
            normal_buffer = QOpenGLBuffer()
            normal_buffer.create()
            normal_buffer.bind()
            normal_buffer.allocate(normals, len(normals) * 4)
            
            tex_coords = np.array(tex_coords, dtype=np.float32)
            tex_coord_buffer = QOpenGLBuffer()
            tex_coord_buffer.create()
            tex_coord_buffer.bind()
            tex_coord_buffer.allocate(tex_coords, len(tex_coords) * 4)
     
            vert_buffers = VertexBuffers()
            vert_buffers.vert_pos_buffer = vert_pos_buffer
            vert_buffers.normal_buffer = normal_buffer
            vert_buffers.tex_coord_buffer = tex_coord_buffer
            vert_buffers.amount_of_vertices = int(len(index_array) / 3)
            
            return vert_buffers
     
    def main():
        QApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
        app = QApplication(sys.argv)
        w = Window()
        w.show()
        sys.exit(app.exec_())
     
    if __name__ == "__main__":
        main()

Для запуска данного примера вам нужно установить следующие пакеты:
> pip install PyQt5
> pip install PySide2
> pip install PyOpenGL
> pip install panda3d
> pip install numpy
Кубик создан и текстурирован в бесплатных программах:
  • Blender - бесплатный 3D-редактор
  • GIMP - бесплатный редактор изображений

Кубик экспортирован из Blender и импортирован в программу из файла формата .dae (COLLADA). Для старта изучения движка Bullet советую книгу: Learning Game Physics With Bullet

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

Движение вверх-вниз от кнопки и мышки
Приветствую всех, Пересматриваю кучу уроков по перемещение объектов, не могу разобраться с вот таким способом. нужно, чтобы при...

Движение двух окружностей вверх / вниз
Нужно чтобы две окружности двигались верх вниз из одного угла в другой. Написал код. Они двигаются вверх вниз но не знаю как сделать чтобы...

Движение вверх, вниз, вправо и влево, но не по диагонали
как реализовать движение фигуры только в таком направление, т.е. вверх, вниз, вправо и влево, но не по диагонали, есть код готового...

Движение лифта вверх и вниз, изображённого в PictureBox
Помогите построить движение лифта вверх и вниз, с графикой просто не дружу. Нужно плавное движение лифта.

Как отследить движение телефона вверх вниз ?
Возник вопрос, как отследить движение телефона вверх вниз? Не рывки и встряхивания , а именно движение Допустим, когда я поднимаю...


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

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Новые блоги и статьи
Использование SDL3-callbacks вместо функции main() на Android, Desktop и WebAssembly
8Observer8 24.01.2026
Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а привычная функция main(). . .
моя боль
iceja 24.01.2026
Выложила интерполяцию кубическими сплайнами www. iceja. net REST сервисы временно не работают, только через Web. Написала за 56 рабочих часов этот сайт с нуля. При помощи perplexity. ai PRO , при. . .
Модель сукцессии микоризы
anaschu 24.01.2026
Решили писать научную статью с неким РОманом
http://iceja.net/ математические сервисы
iceja 20.01.2026
Обновила свой сайт http:/ / iceja. net/ , приделала Fast Fourier Transform экстраполяцию сигналов. Однако предсказывает далеко не каждый сигнал (см ограничения http:/ / iceja. net/ fourier/ docs ). Также. . .
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма). На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
Расчёт переходных процессов в цепи постоянного тока
igorrr37 16.01.2026
/ * Дана цепь(не выше 3-го порядка) постоянного тока с элементами R, L, C, k(ключ), U, E, J. Программа находит переходные токи и напряжения на элементах схемы классическим методом(1 и 2 з-ны. . .
Восстановить юзерскрипты Greasemonkey из бэкапа браузера
damix 15.01.2026
Если восстановить из бэкапа профиль Firefox после переустановки винды, то список юзерскриптов в Greasemonkey будет пустым. Но восстановить их можно так. Для этого понадобится консольная утилита. . .
Сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru