Plotting order of GLMeshItem and GLScatterPlotItem in interactive GUI

36 Views Asked by At

I am creating a gui in python using OpenGL and PyQt5. I'm struggling to get the plotting order correct in a gui I'm making. I am trying to get 3d points to show up on top of the mesh faces, but nothing I do gets the mesh transparency to change, or adds the 3d points on top of the mesh. enter image description here

Here, you can see my gui with the mesh person in white, and some red dots around the waist. I can't get them to appear on top of the mesh.

This is my code:

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QVBoxLayout, QWidget, QHBoxLayout, QSizePolicy
from PyQt5.QtCore import Qt  # Import Qt module for alignment
import pyqtgraph.opengl as gl
import numpy as np

def read_obj_file(file_path):
    """
    Read vertices and faces from an OBJ file.
    """
    vertices = []
    faces = []

    with open(file_path, 'r') as f:
        for line in f:
            parts = line.strip().split()
            if len(parts) == 0 or parts[0] == '#':
                continue
            if parts[0] == 'v':
                vertices.append(list(map(float, parts[1:])))
            elif parts[0] == 'f':
                face = []
                for vertex in parts[1:]:
                    indices = vertex.split('/')
                    face.append(int(indices[0]) - 1)  # OBJ file indices are 1-based
                faces.append(face)

    return np.array(vertices), np.array(faces)

def triangulate_faces(faces):
    """
    Triangulate the quadrilateral faces into triangles.
    """
    triangles = []
    for face in faces:
        # Split each quadrilateral face into two triangles
        triangles.append([face[0], face[1], face[2]])
        triangles.append([face[0], face[2], face[3]])
    return np.array(triangles)


def create_mesh(vertices, faces):
 
    mesh = gl.GLMeshItem(vertexes=vertices, faces=faces, drawEdges=True)
    #how to make edge thickness bigger??
    return mesh

def plane_mesh_intersection(vertices, faces, y_plane):
    """
    Find the intersection points of a plane in the y-direction with a mesh.
    
    Args:
    - vertices (np.array): Array of mesh vertices.
    - faces (np.array): Array of mesh faces.
    - y_plane (float): Y-coordinate of the plane.
    
    Returns:
    - intersection_points (list): List of intersection points as (x, y, z) coordinates.
    """
    intersection_points = []
    
    for face in faces:
        v1, v2, v3 = vertices[face[0]], vertices[face[1]], vertices[face[2]]
        
        # Check if all vertices are on the same side of the plane
        above_plane = v1[1] >= y_plane and v2[1] >= y_plane and v3[1] >= y_plane
        below_plane = v1[1] < y_plane and v2[1] < y_plane and v3[1] < y_plane
        
        if not above_plane and not below_plane:
            # Calculate intersection points with the plane for each edge
            intersections = []
            for v_start, v_end in [(v1, v2), (v2, v3), (v3, v1)]:
                # Check if the edge crosses the plane
                if v_start[1] != v_end[1]:
                    t = (y_plane - v_start[1]) / (v_end[1] - v_start[1])
                    if 0 <= t <= 1:
                        intersection_point = (
                            v_start[0] + t * (v_end[0] - v_start[0]),
                            y_plane,
                            v_start[2] + t * (v_end[2] - v_start[2])
                        )
                        intersections.append(intersection_point)
            
            # Add intersection points to the list
            if intersections:
                intersection_points.extend(intersections)
    
    return intersection_points

def main():
    # Create a PyQtGraph application
    app = QApplication(sys.argv)
    window = QMainWindow()
    window.setWindowTitle('3D Mesh Plot')
    window.setGeometry(200, 200, 900, 700)  # Set initial window size

    # Create a central widget for displaying 3D graphics
    central_widget = QWidget()
    layout = QHBoxLayout()
    central_widget.setLayout(layout)
    window.setCentralWidget(central_widget)

    # Create a widget for displaying 3D graphics
    widget = gl.GLViewWidget()
    widget.setCameraPosition(distance=300, azimuth=-90, elevation=90)

    layout.addWidget(widget)

    # Read vertices and faces from OBJ file
    vertices, faces = read_obj_file('Female.obj')

    # Triangulate the faces
    faces = triangulate_faces(faces)

    # Calculate the center of the mesh
    center = vertices.mean(axis=0)

    # Translate the mesh to center it at the origin
    vertices -= center
    
    # Create the mesh object
    mesh = create_mesh(vertices, faces)
    mesh.setGLOptions('translucent')

    # Add the mesh to the widget
    widget.addItem(mesh)
    
    
    #calculate 
    plane = 0
    test = plane_mesh_intersection(vertices, faces, plane)
    
    # Add intersection points to the widget as spheres
    for point in test:
        sphere = gl.GLScatterPlotItem(pos=np.array([point]), color=(1, 0, 0, 1), size=10)
        widget.addItem(sphere)
    

    # Create a QWidget for displaying text boxes
    text_widget = QWidget()
    text_layout = QVBoxLayout()
    text_widget.setLayout(text_layout)
    layout.addWidget(text_widget)
    layout.setStretch(0, 3)  # Set stretch factor for the 3D graphics widget
    layout.setStretch(1, 1)  # Set stretch factor for the text widget
    
    Labels = ["Height", "Weight", "Chest", "Waist", "Hips"]
    Measurements = [0, 0, 0, 0, 0]
    
    # Add multiple QLabel widgets with gray backgrounds
    for i in range(5):  # Change the range according to the number of text boxes you want
        label = QLabel(Labels[i] + " : " + str(Measurements[i]))
        label.setAlignment(Qt.AlignCenter)  # Center the text horizontally and vertically
        label.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
        label.setStyleSheet("background-color: lightgray; border: 1px solid gray; padding: 5px;")
        text_layout.addWidget(label)
        
    # Start the application event loop
    window.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()
1

There are 1 best solutions below

0
Emma On

I hope this helps someone, but I was able to kind of fix this by modifying the shading of the mesh.

def create_mesh(vertices, faces):
 
    mesh = gl.GLMeshItem(vertexes=vertices, faces=faces, drawEdges=True)
    #how to make edge thickness bigger??
    
    shader = 'shaded'  # Possible values: 'normalColor', 'edgeHilight', 'heightColor', 'colored'
    mesh.setShader(shader)
    
    return mesh

See the mesh and 3D points here!