2 votes

La dimension Z disparaît dans le monde moderne ?

J'ai essayé de faire pivoter un objet mais après la rotation, j'ai réalisé qu'il était juste plat. Ce qui est étrange, c'est que je peux clairement voir que les entrées pour le z dim sont là, il n'est tout simplement pas pris en compte. Voici mon code :

import moderngl
from PyQt5 import QtOpenGL, QtCore, QtGui
from PyQt5.QtCore import Qt, pyqtSignal
import numpy as np
from pyrr import matrix44

cube_verts4 = np.array([
    -1.0, 1.0, -1.0, 1.0,
    -1.0, -1.0, -1.0, 1.0,
    1.0, -1.0, -1.0, 1.0,
    1.0, 1.0, -1.0, 1.0,
    -1.0, 1.0, 1.0, 1.0,
    -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)

cube_ibo_idxs = np.array([
    0, 1, 2,
    2, 3, 1,
    3, 2, 6,
    6, 5, 3,
    5, 6, 7,
    7, 4, 5,
    4, 7, 1,
    1, 0, 4,
    0, 3, 5,
    5, 4, 0,
    1, 7, 6,
    6, 2, 1

], dtype=np.int32)

class OpenGLWindowWidget(QtOpenGL.QGLWidget):
    vsync = True
    remove_event = pyqtSignal(str)

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.gl_version = (4, 3)
        fmt = QtOpenGL.QGLFormat()
        # need compute shader stuff
        fmt.setVersion(self.gl_version[0], self.gl_version[1])
        fmt.setProfile(QtOpenGL.QGLFormat.CoreProfile)
        fmt.setDepthBufferSize(24)
        fmt.setDoubleBuffer(True)
        fmt.setSwapInterval(1 if self.vsync else 0)
        self.ctx = None
        self.timer = QtCore.QTimer(self)
        self.timer.timeout.connect(self.update)
        self.timer.start(16)
        self.last_mouse_pos = None

        self.rotation_x = 0
        self.rotation_y = 0

    def mousePressEvent(self, event: QtGui.QMouseEvent) -> None:
        self.last_mouse_pos = event.pos()

    def mouseMoveEvent(self, event: QtGui.QMouseEvent) -> None:
        dx = event.x() - self.last_mouse_pos.x()
        dy = event.y() - self.last_mouse_pos.y()
        if event.buttons() & Qt.LeftButton:
            self.rotation_x += dx * 0.01
            self.rotation_y += dy * 0.01

        self.last_mouse_pos = event.pos()

    @property
    def gl_version_code(self) -> int:
        return self.gl_version[0] * 100 + self.gl_version[1] * 10

    @property
    def aspect_ratio(self):
        return self.width() / self.height()

    def initializeGL(self) -> None:
        self.ctx = moderngl.create_context(
            require=self.gl_version_code)
        self.prog = self.ctx.program(
            vertex_shader='''
                               #version 330
                               in vec4 vertex;
                               in float power;
                               uniform mat4 mvp_matrix;
                               void main() {
                                   gl_Position = vec4(mvp_matrix * vertex);
                               }
                           ''',
            fragment_shader='''
                                   #version 330
                                   out vec4 color;
                                   void main() {
                                       color = vec4(0.0, 0.0, 0.0, 1.0);
                                   }
                                   ''',
        )

        self.mvp_matrix = self.prog["mvp_matrix"]

        self.vbo = self.ctx.buffer(
            cube_verts4.astype('f4').tobytes())
        self.ibo = self.ctx.buffer(
            cube_ibo_idxs.astype('i4').tobytes())
        vao_content = [
            # 4 floats are assigned to the 'in' variable named 'vertex' in the shader code
            (self.vbo, '4f', 'vertex'),
        ]
        self.vao = self.ctx.vertex_array(self.prog, vao_content,
                                         self.ibo)

    def paintGL(self):
        target_width = 2
        target_height = 2
        r_aspect_ratio = target_width / target_height
        if self.aspect_ratio > r_aspect_ratio:
            v_a = self.aspect_ratio / r_aspect_ratio
            projection = matrix44.create_orthogonal_projection_matrix(
                -v_a * target_width / 2.0,
                v_a * target_width / 2.0, -target_height / 2.0,
                target_height / 2.0, 0, 100, dtype=np.float32)
        else:
            a_v = r_aspect_ratio / self.aspect_ratio
            projection = matrix44.create_orthogonal_projection_matrix(
                -target_width / 2.0, target_width / 2.0,
                -a_v * target_height / 2.0,
                a_v * target_height / 2.0,
                0, 100, dtype=np.float32)

        rotate = matrix44.create_from_y_rotation(
            self.rotation_x) * matrix44.create_from_x_rotation(
            self.rotation_y)

        self.mvp_matrix.write((rotate * projection).astype('f4').tobytes())
        self.ctx.viewport = (0, 0, self.width(), self.height())
        self.ctx.clear(0.0, 1.0, 1.0)
        self.vao.render()
        self.ctx.finish()

C'est ce que j'en retire quand je fais la rotation.

enter image description here

enter image description here

enter image description here

Je me serais attendu à la silhouette d'un cube, à la place j'obtiens la silhouette d'un avion.

Je ne suis même pas sûr de ce qui pourrait causer cet effet. J'ai d'abord pensé que cela avait quelque chose à voir avec l'alignement de vec3, mais j'ai remplacé mon code vertex + vbo pour utiliser vec4s à la place et cela ne fonctionne toujours pas. Je ne sais pas comment ma profondeur est "supprimée". Je ne suis pas familier avec pyrr Alors peut-être que la transformation de la matrice est incorrecte ?

3voto

Rabbid76 Points 52493

Les indices des éléments ne forment pas un cube. Utilisez les indices suivants :

cube_ibo_idxs = np.array([
    0, 1, 2,   0, 2, 3,
    3, 2, 6,   3, 6, 7,
    7, 6, 5,   7, 5, 4,
    7, 4, 0,   7, 0, 3,
    4, 5, 1,   4, 1, 0,
    1, 5, 6,   1, 6, 2
], dtype=np.int32)

pyrr Matrix44 renvoient un numpy.array .
pour le tableau, * signifie une multiplication par éléments, tandis que @ signifie la multiplication de la matrice. Voir array . Donc vous devez utiliser @ à la place de * . Vous pouvez également utiliser numpy.matmul .

Dans la projection orthographique, le plan proche est fixé à 0 et le plan éloigné à 100.

projection = matrix44.create_orthogonal_projection_matrix(
               v_a * -target_width / 2.0, v_a * target_width / 2.0,
               -target_height / 2.0, target_height / 2.0,
               0, 100, dtype=np.float32)

Le centre de la géométrie étant à (0, 0, 0), le maillage du cube est partiellement coupé par le plan proche du volume de vue du cuboïde. Soit vous changez le plan proche (par exemple -100), soit vous dessinez le cube entre les plans proche et lointain. Cela signifie que vous devez translater le maillage le long de l'axe z. Puisque l'axe z (de l'espace de vue) pointe vers l'extérieur du port de vue (en Droitier ), vous devez translater le maillage dans la direction négative de z (par ex. -3 ) :

rotate = matrix44.create_from_y_rotation(-self.rotation_x) @ \
         matrix44.create_from_x_rotation(-self.rotation_y) @ \
         matrix44.create_from_translation(np.array([0, 0, -3], dtype=np.float32)) 

En outre, je recommande d'activer l'option Test de profondeur . Voir ModernGL - Contexte :

self.ctx.enable(moderngl.DEPTH_TEST)

Utilisez la fonction suivante pour dessiner la géométrie :

def paintGL(self):
    target_width = 4
    target_height = 4
    r_aspect_ratio = target_width / target_height
    if self.aspect_ratio > r_aspect_ratio:
        v_a = self.aspect_ratio / r_aspect_ratio
        projection = matrix44.create_orthogonal_projection_matrix(
            v_a * -target_width / 2.0, v_a * target_width / 2.0,
            -target_height / 2.0, target_height / 2.0,
            0, 100, dtype=np.float32)
    else:
        a_v = r_aspect_ratio / self.aspect_ratio
        projection = matrix44.create_orthogonal_projection_matrix(
            -target_width / 2.0, target_width / 2.0,
            -a_v * target_height / 2.0, a_v * target_height / 2.0,
            0, 100, dtype=np.float32)

    rotate = matrix44.create_from_y_rotation(-self.rotation_x) @ \
                matrix44.create_from_x_rotation(-self.rotation_y) @ \
                matrix44.create_from_translation(np.array([0, 0, -3], dtype=np.float32))      

    self.mvp_matrix.write((rotate @ projection).astype('f4').tobytes())
    self.ctx.viewport = (0, 0, self.width(), self.height())
    self.ctx.clear(0.0, 1.0, 1.0)
    self.ctx.enable(moderngl.DEPTH_TEST)
    self.vao.render()
    self.ctx.finish()

Si vous utilisez le vertex shader suivant

#version 330
in vec4 vertex;
in float power;
out vec4 v_clip_pos; 
uniform mat4 mvp_matrix;
void main() {
    v_clip_pos = mvp_matrix * vertex;
    gl_Position = v_clip_pos;
}

et le fragment shader

#version 330
in vec4 v_clip_pos; 
out vec4 color;
void main() {

    vec3  ndc_pos = v_clip_pos.xyz / v_clip_pos.w;
    vec3  dx      = dFdx( ndc_pos );
    vec3  dy      = dFdy( ndc_pos );

    vec3 N = normalize(cross(dx, dy));
    N *= sign(N.z);
    vec3 L = vec3(0.0, 0.0, 1.0); 
    float NdotL = dot(N, L); 

    vec3 diffuse_color = vec3(0.5) * NdotL;
    color              = vec4( diffuse_color.rgb, 1.0 );
}

vous pouvez alors obtenir un léger effet 3D.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X