Nagarjun Vinukonda
Nagarjun Vinukonda

Reputation: 21

How to setup light source position and shading: with Pyqtgraph: GLMeshItem?

I am using pyqtgraph.opengl for graphics and display of STL files on my UI. I am using phong shading technique called 'shaded' param with pyqtgraph.opengl.GLMeshItem API. But I am having a dark color shade projection more just like the following person posted in the link. Barrett Anderies issues with pyqtgraph dark images

The following is my dark shaded image below:

very dark shade of my stl files

It seems like the light source is coming from below. I want to move this light source in the camera point of view. I am not sure how as I couldn't find any specific API on the documentation. pyqt5 documentation

This is my UI code for displaying stl files:

#!/usr/bin/env python3
import sys
import rclpy
from rclpy.qos import QoSProfile
from geometry_msgs.msg import Point
from std_msgs.msg import Bool
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QPushButton, QLineEdit, QVBoxLayout, QLabel, QMenuBar, QStatusBar, QOpenGLWidget
from PyQt5 import QtCore , QtGui
import pyqtgraph.opengl as gl
import numpy as np
from stl import mesh
import OpenGL.GL as ogl  # Import the OpenGL module from PyOpenGL


class GLViewWidgetWithBackground(gl.GLViewWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        # Ensure the clear color is set during initialization
        self.setBackgroundColor(QtGui.QColor(85, 126, 214))

        
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1007, 730)
        font = QtGui.QFont()
        font.setPointSize(13)
        MainWindow.setFont(font)
        self.centralwidget = QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.calibrate_button = QPushButton(self.centralwidget)
        self.calibrate_button.setGeometry(QtCore.QRect(50, 350, 89, 25))
        self.calibrate_button.setObjectName("calibrate_button")
        self.move_button = QPushButton(self.centralwidget)
        self.move_button.setGeometry(QtCore.QRect(50, 280, 89, 25))
        self.move_button.setObjectName("move_button")
        self.stop_button = QPushButton(self.centralwidget)
        self.stop_button.setGeometry(QtCore.QRect(170, 280, 89, 25))
        self.stop_button.setObjectName("stop_button")
        self.x_input = QLineEdit(self.centralwidget)
        self.x_input.setGeometry(QtCore.QRect(10, 60, 51, 21))
        self.x_input.setText("")
        self.x_input.setObjectName("x_input")
        self.y_input = QLineEdit(self.centralwidget)
        self.y_input.setGeometry(QtCore.QRect(80, 60, 51, 21))
        self.y_input.setText("")
        self.y_input.setObjectName("y_input")
        self.z_input = QLineEdit(self.centralwidget)
        self.z_input.setGeometry(QtCore.QRect(150, 60, 51, 21))
        self.z_input.setText("")
        self.z_input.setObjectName("z_input")
        self.publish_coords_button = QPushButton(self.centralwidget)
        self.publish_coords_button.setGeometry(QtCore.QRect(220, 60, 89, 25))
        self.publish_coords_button.setObjectName("publish_coords_button")
        self.theta1 = QLineEdit(self.centralwidget)
        self.theta1.setGeometry(QtCore.QRect(10, 180, 51, 21))
        self.theta1.setObjectName("theta1")
        self.theta2 = QLineEdit(self.centralwidget)
        self.theta2.setGeometry(QtCore.QRect(80, 180, 51, 21))
        self.theta2.setObjectName("theta2")
        self.theta3 = QLineEdit(self.centralwidget)
        self.theta3.setGeometry(QtCore.QRect(150, 180, 51, 21))
        self.theta3.setObjectName("theta3")
        self.publish_angles_button = QPushButton(self.centralwidget)
        self.publish_angles_button.setGeometry(QtCore.QRect(220, 180, 89, 25))
        font = QtGui.QFont()
        font.setPointSize(13)
        self.publish_angles_button.setFont(font)
        self.publish_angles_button.setObjectName("publish_angles_button")
        self.min_q1 = QLabel(self.centralwidget)
        self.min_q1.setGeometry(QtCore.QRect(10, 210, 61, 21))
        font = QtGui.QFont()
        font.setPointSize(8)
        self.min_q1.setFont(font)
        self.min_q1.setObjectName("min_q1")
        self.max_q1 = QLabel(self.centralwidget)
        self.max_q1.setGeometry(QtCore.QRect(10, 150, 61, 21))
        font = QtGui.QFont()
        font.setPointSize(8)
        self.max_q1.setFont(font)
        self.max_q1.setObjectName("max_q1")
        self.min_q2 = QLabel(self.centralwidget)
        self.min_q2.setGeometry(QtCore.QRect(80, 210, 81, 21))
        font = QtGui.QFont()
        font.setPointSize(8)
        self.min_q2.setFont(font)
        self.min_q2.setObjectName("min_q2")
        self.max_q2 = QLabel(self.centralwidget)
        self.max_q2.setGeometry(QtCore.QRect(80, 150, 81, 21))
        font = QtGui.QFont()
        font.setPointSize(8)
        self.max_q2.setFont(font)
        self.max_q2.setObjectName("max_q2")
        self.min_t3 = QLabel(self.centralwidget)
        self.min_t3.setGeometry(QtCore.QRect(150, 210, 51, 16))
        font = QtGui.QFont()
        font.setPointSize(8)
        self.min_t3.setFont(font)
        self.min_t3.setAlignment(QtCore.Qt.AlignBottom|QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft)
        self.min_t3.setObjectName("min_t3")
        self.max_t3 = QLabel(self.centralwidget)
        self.max_t3.setGeometry(QtCore.QRect(150, 150, 61, 21))
        font = QtGui.QFont()
        font.setPointSize(8)
        self.max_t3.setFont(font)
        self.max_t3.setObjectName("max_t3")
        self.ManualMode = QPushButton(self.centralwidget)
        self.ManualMode.setGeometry(QtCore.QRect(170, 350, 89, 25))
        self.ManualMode.setObjectName("ManualMode")

        # 3D view widget
        self.openGLWidget = GLViewWidgetWithBackground(self.centralwidget)
        self.openGLWidget.setGeometry(QtCore.QRect(340, 60, 641, 621))
        self.openGLWidget.setObjectName("openGLWidget")

        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 1007, 25))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.calibrate_button.setText(_translate("MainWindow", "Calibrate"))
        self.move_button.setText(_translate("MainWindow", "Move"))
        self.stop_button.setText(_translate("MainWindow", "STOP"))
        self.x_input.setPlaceholderText(_translate("MainWindow", "x"))
        self.y_input.setPlaceholderText(_translate("MainWindow", "y"))
        self.z_input.setPlaceholderText(_translate("MainWindow", "z"))
        self.publish_coords_button.setText(_translate("MainWindow", "Set IK"))
        self.theta1.setPlaceholderText(_translate("MainWindow", "q1"))
        self.theta2.setPlaceholderText(_translate("MainWindow", "q2"))
        self.theta3.setPlaceholderText(_translate("MainWindow", "t3"))
        self.publish_angles_button.setText(_translate("MainWindow", "Set FK"))
        self.min_q1.setText(_translate("MainWindow", "min: -40"))
        self.max_q1.setText(_translate("MainWindow", "max: 40"))
        self.min_q2.setText(_translate("MainWindow", "min: -29.24"))
        self.max_q2.setText(_translate("MainWindow", "max: 50.17"))
        self.min_t3.setText(_translate("MainWindow", "min: 0"))
        self.max_t3.setText(_translate("MainWindow", "max: 150"))
        self.ManualMode.setText(_translate("MainWindow", "Manual"))


class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        # self.setStyleSheet("background-color: cyan;")  # Set the background color here

        # Initialize ROS node
        rclpy.init()

        # Create ROS publisher
        self.node = rclpy.create_node('gui_publisher')
        qos = QoSProfile(depth=10)
        self.pub_cal = self.node.create_publisher(Bool, 'cal_click', qos)
        self.pub_move = self.node.create_publisher(Bool, 'move_click', qos)
        self.pub_manual = self.node.create_publisher(Bool, 'manual_click', qos)
        self.pub_stop = self.node.create_publisher(Bool, 'stop_click', qos)
        self.pub_coords = self.node.create_publisher(Point, 'coordinates', qos)
        self.pub_angles = self.node.create_publisher(Point, 'angles', qos)
        self.pub_close = self.node.create_publisher(Bool, 'close_click', qos)

        # Connect button clicks to methods
        self.calibrate_button.clicked.connect(self.on_calibrate_clicked)
        self.move_button.clicked.connect(self.on_move_clicked)
        self.ManualMode.clicked.connect(self.on_manual_clicked)
        self.stop_button.clicked.connect(self.on_stop_clicked)
        self.publish_coords_button.clicked.connect(self.on_publish_coords_clicked)
        self.publish_angles_button.clicked.connect(self.on_publish_angles_clicked)

        self.show()

        # Define colors
        white_color = [253/255.0, 253/255.0, 253/255.0, 0.9]
        purple_transparent = [128/255.0, 0, 128/255.0, 1.0]
        edgeColor_white = [140/255.0, 140/255.0, 140/255.0, 1.0]
        edgeColor_purple = [120/255.0, 0, 120/255.0, 1.0]

        # # Load STL files with specified colors
        stl_files = [
            ("/home/nagarjun/ros2_ws/src/robot_parts/ROT_Link_v2.STL", white_color, edgeColor_white),
            ("/home/nagarjun/ros2_ws/src/robot_parts/Nut_v2.STL", white_color, edgeColor_white),
            ("/home/nagarjun/ros2_ws/src/robot_parts/RCM_CenterLink_v2.STL", white_color, edgeColor_white),
            ("/home/nagarjun/ros2_ws/src/robot_parts/RCM_SwingArm_Back_v2.STL", white_color, edgeColor_white),
            ("/home/nagarjun/ros2_ws/src/robot_parts/RCM_Parallelogram_Up_v2.STL", white_color, edgeColor_white),
            ("/home/nagarjun/ros2_ws/src/robot_parts/RCM_Parallelogram_Down_v2.STL", white_color, edgeColor_white),
            ("/home/nagarjun/ros2_ws/src/robot_parts/RCM_SwingArm_Front_v2.STL", white_color, edgeColor_white),
            ("/home/nagarjun/ros2_ws/src/robot_parts/NeedleHolder_v2.STL", white_color, edgeColor_white),
            ("/home/nagarjun/ros2_ws/src/robot_parts/Needle_v2.STL", white_color, edgeColor_white),
            ("/home/nagarjun/ros2_ws/src/robot_parts/Frame_v2.STL", purple_transparent, edgeColor_purple)
        ]

        for stl_file, color, edgeColor in stl_files:
            self.load_stl(stl_file,color, edgeColor)

    def on_calibrate_clicked(self):
        msg = Bool()
        msg.data = True
        self.pub_cal.publish(msg)
        print("Cal Click")

    def on_move_clicked(self):
        msg = Bool()
        msg.data = True
        self.pub_move.publish(msg)
        print("Move Click")

    def on_manual_clicked(self):
        msg = Bool()
        msg.data = True
        self.pub_manual.publish(msg)
        print("Manual Click")

    def on_stop_clicked(self):
        msg = Bool()
        msg.data = True
        self.pub_stop.publish(msg)
        print("Stop button clicked!")

    def on_publish_coords_clicked(self):
        x = float(self.x_input.text())
        y = float(self.y_input.text())
        z = float(self.z_input.text())
        msg = Point()
        msg.x = x
        msg.y = y
        msg.z = z
        self.pub_coords.publish(msg)
        print(f"Published Coordinates: x={x}, y={y}, z={z}")

    def on_publish_angles_clicked(self):
        q1 = float(self.theta1.text())
        q2 = float(self.theta2.text())
        t3 = float(self.theta3.text())
        msg = Point()
        msg.x = q1
        msg.y = q2
        msg.z = t3
        self.pub_angles.publish(msg)
        print(f"Published angles: q1={q1}, q2={q2}, t3={t3}")

    def closeEvent(self, event):
        msg = Bool()
        msg.data = True
        self.pub_close.publish(msg)
        super().closeEvent(event)

    def load_stl(self, filepath, color, edgeColor):
        your_mesh = mesh.Mesh.from_file(filepath)
        # each vertex is a 3 coordinates
        vertices = np.zeros((your_mesh.vectors.size, 3))
        # Each face (triangle) is represented by three vertex indices, hence the shape[0] which is no. of vertices
        faces = np.zeros((your_mesh.vectors.shape[0], 3), dtype=int)
        vertex_id = 0
        #This loop iterates over each triangle in the mesh.
        for i, v in enumerate(your_mesh.vectors):
            #This nested loop iterates over each vertex of the current triangle.
            for j in range(3):
                #This line assigns the coordinates of the current vertex 'v[j, :]' to the vertices array at the position vertex_id.
                vertices[vertex_id, :] = v[j, :]
                faces[i, j] = vertex_id
                vertex_id += 1

        # Define white color with full opacity
        colors = np.array([color] * faces.shape[0])

        mesh_item = gl.GLMeshItem(vertexes=vertices, faces=faces, edgeColor = edgeColor, drawEdges=False, drawFaces=True, shader='shaded' ,smooth=False, faceColors=colors)
        self.openGLWidget.addItem(mesh_item)


def main():
    # create pyqt5 app
    app = QApplication(sys.argv)

    # create the instance of our Window
    window = MainWindow()
    window.show()

    # start the app
    sys.exit(app.exec())

if __name__ == '__main__':
    main()

The have tried using vertex shader and fragment shader but I still dont have any better results.

I am expecting the light should come from camera point of view... Like if I can change the position of the light source.

Upvotes: 1

Views: 123

Answers (0)

Related Questions