Widgets in maya viewport

601 views
Skip to first unread message

Daniele Dolci

unread,
Mar 29, 2022, 9:46:22 AM3/29/22
to Python Programming for Autodesk Maya
Hi All! 

I am playing around in Maya trying to achieve a UI similar to the one implemented in Ragdoll by Marcus Ottosson. I have a couple of questions. The first is probably going to be trivial: How do I make the background of this label transparent? I attach below a minimal test to reproduce it:
Capture.PNG

```python
import shiboken2
import sys
import os
from maya import cmds
from maya.api import OpenMayaUI as omui
from maya.OpenMayaUI import MQtUtil

try:
    from PySide2 import QtCore, QtWidgets, QtGui
except ImportError:
    from Qt import QtCore, QtWidgets

CSS = """
QDialog #View {
background-color: rgba(0, 0, 0, 0);
}

QWidget #View {
background-color: rgba(0, 0, 0, 0);
}

QLabel {
    color: #eee;
    font-size: 12px;
    background-color: rgba(0, 0, 0, 0);
}
"""
class View(QtWidgets.QDialog):

    def __init__(self):
        super(View, self).__init__()
        self._init_window()
        self._init_ui()

    def _init_window(self):
        self.setWindowTitle("UI")
        flags = QtCore.Qt.WindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.Dialog)
        self.setWindowFlags(flags)
        panel = cmds.playblast(activeEditor=True)
        self.setAttribute(QtCore.Qt.WA_NoSystemBackground, True)
        self.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
        self.setAttribute(QtCore.Qt.WA_PaintOnScreen)
        self.setObjectName("View")

        # view = omui.M3dView.getM3dViewFromModelEditor(panel)
        view =  MQtUtil.findControl(panel)
        self._widget = shiboken2.wrapInstance(long(view), QtWidgets.QDialog)

        self._widget.setObjectName("View")
        self._widget.setAttribute(QtCore.Qt.WA_NoSystemBackground, True)
        self._widget.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
        self._widget.setAttribute(QtCore.Qt.WA_PaintOnScreen)

    def _init_ui(self):
        self._help_lbl = QtWidgets.QLabel("ToolTip", self._widget)
       
        self._help_lbl.move(self._widget.width() - 100, 10)

        self._help_lbl.show()

        self._help_lbl.setStyleSheet(CSS)

    def update(self, *args, **kwargs):
        super(View, self).update(*args, **kwargs)
        self._setup_btn.move(250, 1000)
        self._create_btn.move(200, 1000)
        self._build_btn.move(300, 1000)
        self._optimize_btn.move(1400, 1000)
        self._help_lbl.move(self._widget.width() - 100, 10)


View()
```

the second question is, what would be the best way to have the widget to be drawn again when the user change the size of the UI, when he switches from attribute editor to channel box etc? Please see attached gif:

ui.gif

Marcus Ottosson

unread,
Jul 19, 2022, 5:11:41 PM7/19/22
to Python Programming for Autodesk Maya
Oh hey, I missed this!

For reference, here's the UI Daniele is referring to.


On the one hand, it's totally possible to make a transparent widget that overlays the viewport. On the other hand, I did not use Qt for this. That UI is actually rendered with OpenGL and DirectX, directly into the viewport, as a custom Maya node. The transparent background is a polygon surface with transparency, rendered very near the camera so as to not clip with other 3d geometry, and the text is.. textures. Under the hood, it's drawn with an MPxDrawOverride.

Now, I mentioned that it is possible to make a transparend widget, but it does get a bit finicky. MacOS for example doesn't let you do it. For whatever reason, anything 3d has to appear on-top of any transparent widget. From what I gather, this is how their window manager is designed. For Linux and Windows, it's possible, but finicky. Your best bet is making a full-blown window, but make it borderless. For transparency, your best bet is physically screencapturing the area underneath the widget, and using that as a background image to your widget.

Like I said, finicky. The issue you're having with needing to move and resize your widget as the viewport changes.. Yes, that is going to be challenging. Maya doesn't do a good job in letting you interact with the widget that holds onto the 3d surface, so it's not obvious how to get notified to changes and what those changes are.

But it is possible! I had a conversation recently with the BroDynamics developer who I'll link to this thread in case he's got some things to share.

nixe...@gmail.com

unread,
Jul 26, 2022, 7:00:58 AM7/26/22
to Python Programming for Autodesk Maya
Hi!

Yes, Marcus is correct, there is a way to achieve this through Qt. Here's my implementation:

The gist of it is correct, it's just grabbing a screenshot of the underlying 3d view through something like omui.M3dView, cropping it based on widget position and using this image as a background for the widget.
But this method has a ton of downsides. One of them is performance, trying to do this every frame or even on every viewport redraw will drop viewport FPS drastically. It can easily bring it from 200 to 20. So you need to think about how to best optimize when and how it updates it's background. Another is that sometimes you can get black background depending on which one of many viewports maya renders is active, for example when opening Hypershade, at least depending on how you get the screenshot.

As for redrawing, I made my widget a child of the viewport, and it redraws it's background any time it's own size is changed and at 4FPS. It works for my particular tool, especially since it is designed to take up just a thin line of viewport at the top, but it's unlikely that it will work well for most other tools which need to cover up more of the viewport.

Matin Falahmanesh

unread,
Jan 8, 2024, 8:58:20 AMJan 8
to Python Programming for Autodesk Maya
Hi! How did you manage to render with OpenGL and DirectX directly into the viewport? Are you just using MPxDrawOverride? If so, how can you achieve widget-like behavior (like a button) with DrawOverride classes?

Bests,
-MatinF

Marcus Ottosson

unread,
Jan 8, 2024, 9:34:55 AMJan 8
to python_in...@googlegroups.com

Are you just using MPxDrawOverride? If so, how can you achieve widget-like behavior (like a button) with DrawOverride classes?

Yes! You can ask Maya for the OpenGL or DirectX context, and use it like you would in a normal standalone application.

If so, how can you achieve widget-like behavior (like a button) with DrawOverride classes?

There are likely many ways, but we went the route of implementing a MPxManipulator which captures mouse movements and blocks other Maya inputs at the same time. From there, you would draw graphics and interpret mouse inputs like any normal application.

This does deserve a longer write-up, because I don’t know of any resource for it. I cautiously experimented my way forwards and was happy and surprised it “just worked”.


--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/84965d5e-1787-4528-a583-1adb83f96780n%40googlegroups.com.

Daniele Dolci

unread,
Jan 8, 2024, 9:45:17 AMJan 8
to Python Programming for Autodesk Maya
@Marcus I know you are very busy bringing awesome technology in the industry, but It would be so awesome if at some point you could share some minimal working code or a small tutorial about this. 

Carlos Rico Adega

unread,
Jan 8, 2024, 9:48:58 AMJan 8
to python_in...@googlegroups.com
Amen, 😀. Happy New Year.



--
Carlos Rico Adega
-------------------------------------
LinkedIn
carlos....@gmail.com
Reply all
Reply to author
Forward
0 new messages