I using the following action to generate ambient occlusion maps for models in maya:
Create and assign aiAmbientOcclusion to my model (the one I want to generate oa maps for).
Then, I go Arnold>Utilities>Render Selection To Texture.
Since this process is always the same I want to write a python script to automate it unfortunately I haven't found many useful examples about writing scripts for Arnold.
To add this functionality I must:
import mtoa.renderToTexture
that script is located in
the_way_to_my_install_folder/solidangle/mtoa/2017/scripts/mtoa
I saw that the script defines the class MtoARenderToTexture and I should pass an object to it. Now.
What kind of object I mush use and is there some sort of documentation for MtoARenderToTexture class?
I was able to do what I wanted using ether this tutorial and extending MtoARenderToTexture class.
I do not iclude all my scripts that load scene and manage scenes files as they very specific to my needs, but still think it's a good idea to share some very basic and fundamental elements that may be useful for some new entries as myself.
This is how my extended class looks like
import mtoa.renderToTexture as renderToTexture
import maya.cmds as cmds
class rkMtoaRtoT(renderToTexture.MtoARenderToTexture):
def __init__(self):
renderToTexture.MtoARenderToTexture.__init__(self)
self.dFolder = '~'
self.dResolution = 1024
self.dCameraSamples = 5
def doAutomaticExport(self):
renderToTexture.MtoARenderToTexture.create(self)
cmds.textFieldButtonGrp('outputFolder', e=True, tx=self.dFolder)
cmds.intFieldGrp('resolution', e=True, v1=self.dResolution)
cmds.intFieldGrp('aa_samples', e=True, v1=self.dCameraSamples)
renderToTexture.MtoARenderToTexture.doExport(self)
Related
I am writing in Python, sometimes calling certain aspects of maxscript and I have gotten most of the basics to work. However, I still don't understand FPValues. I don't even understand while looking through the examples and the max help site how to get anything meaningful out of them. For example:
import MaxPlus as MP
import pymxs
MPEval = MP.Core.EvalMAXScript
objectList = []
def addBtnCheck():
select = MPEval('''GetCurrentSelection()''')
objectList.append(select)
print(objectList)
MPEval('''
try (destroyDialog unnamedRollout) catch()
rollout unnamedRollout "Centered" width:262 height:350
(
button 'addBtn' "Add Selection to List" pos:[16,24] width:88 height:38
align:#left
on 'addBtn' pressed do
(
python.Execute "addBtnCheck()"
)
)
''')
MP.Core.EvalMAXScript('''createDialog unnamedRollout''')
(I hope I got the indentation right, pretty new at this)
In the above code I successfully spawned my rollout, and used a button press to call a python function and then I try to put the selection of a group of objects in a variable that I can control through python.
The objectList print gives me this:
[<MaxPlus.FPValue; proxy of <Swig Object of type 'Autodesk::Max::FPValue *' at 0x00000000846E5F00> >]
When used on a selection of two objects. While I would like the object names, their positions, etc!
If anybody can point me in the right direction, or explain FPValues and how to use them like I am an actual five year old, I would be eternally grateful!
Where to start, to me the main issue seems to be the way you're approaching it:
why use MaxPlus at all, that's an low-level SDK wrapper as unpythonic (and incomplete) as it gets
why call maxscript from python for things that can be done in python (getCurrentSelection)
why use maxscript to create UI, you're in python, use pySide
if you can do it in maxscript, why would you do it in python in the first place? Aside from faster math ops, most of the scene operations will be orders of magnitude slower in python. And if you want, you can import and use python modules in maxscript, too.
import MaxPlus as MP
import pymxs
mySel = mp.SelectionManager.Nodes
objectList = []
for each in mySel:
x = each.Name
objectList.append(x)
print objectList
The easiest way I know is with the
my_selection = rt.selection
command...
However, I've found it works a little better for me to throw it into a list() function as well so I can get it as a Python list instead of a MAXscript array. This isn't required but some things get weird when using the default return from rt.selection.
my_selection = list(rt.selection)
Once you have the objects in a list you can just access its attributes by looking up what its called for MAXscript.
for obj in my_selection:
print(obj.name)
I'm wanting to detect when the user has pasted something in ANY application, so I can follow it up with copying a new item into the clipboard (Use case: I have a list of items I'm copying from a database one-by-one into a web-page, and would like to automatically put the next one in the clipboard once I've finished pasting.)
Currently I have a button using Tkinter that copies a field when pressed using the following code.
self.root.clipboard_clear()
self.root.clipboard_append(text)
What I need then would be some way to detect when a paste has been performed in another application, so I can then load in the next item into the clipboard. I would like it to work on Win/Mac/Linux as I work across all three. Any ideas?
As Leon's answer points out, under standard conditions, it is unlikely that you will be able to detect any use of copied objects once you've released them into the wild. However, most modern OSes support something called "delayed rendering". Not only can the format of the selection be negotiated between host and destination, but it is not advisable to copy large pieces of memory without first knowing where they are going. Both Windows and X provide a way of doing exactly what you want through this mechanism.
Rather than go into the details of how each OS implements their clipboard API, let's look at a fairly standard cross-plarform package: PyQt5. Clipboard access is implemented through the QtGui.QClipBoard class. You can trigger delayed rendering by avoiding the convenience methods and using setMimeData. In particular, you would create a custom QtCore.QMimeData subclass that implements retreiveData to fetch upon request rather than just storing the data in the clipboard. You will also have to set up your own implementations of hasFormat and formats, which should not be a problem. This will allow you to dynamically negotiate the available formats upon request, which is how delayed rendering is normally implemented.
So now let's take a look at a small application. You mentioned in the question that you have a list of items that you would like to copy successively once the first one has been copied. Let's do exactly that. Our custom retrieveData implementation will convert the current selection to a string, encode it in UTF-8 or whatever, move the selection forward, and copy that into the clipboard:
from PyQt5.QtCore import Qt, QMimeData, QStringListModel, QTimer, QVariant
from PyQt5.QtGui import QClipboard
from PyQt5.QtWidgets import QAbstractItemView, QApplication, QListView
class MyMimeData(QMimeData):
FORMATS = {'text/plain'}
def __init__(self, item, hook=None):
super().__init__()
self.item = item
self.hook = hook
def hasFormat(self, fmt):
return fmt in self.FORMATS
def formats(self):
# Ensure copy
return list(self.FORMATS)
def retrieveData(self, mime, type):
if self.hasFormat(mime):
if self.hook:
self.hook()
return self.item
return QVariant()
class MyListView(QListView):
def keyPressEvent(self, event):
if event.key() == Qt.Key_C and event.modifiers() & Qt.ControlModifier:
self.copy()
else:
super().keyPressEvent(event)
def nextRow(self):
current = self.selectedIndexes()[0]
row = None
if current:
row = self.model().index(current.row() + 1, current.column())
if row is None or row.row() == -1:
row = self.model().index(0, current.column())
self.setCurrentIndex(row)
QTimer.singleShot(1, self.copy)
def copy(self, row=None):
if row is None:
row = self.selectedIndexes()[0]
data = MyMimeData(row.data(), self.nextRow)
QApplication.clipboard().setMimeData(data, QClipboard.Clipboard)
model = QStringListModel([
"First", "Second", "Third", "Fourth", "Fifth",
"Sixth", "Seventh", "Eighth", "Ninth", "Tenth",
])
app = QApplication([])
view = MyListView()
view.setSelectionMode(QAbstractItemView.SingleSelection)
view.setModel(model)
view.show()
app.exec_()
The QTimer object here is just a hack to quickly get a separate thread to run the copy. Attempting to copy outside Qt space triggers some thread-related problems.
The key here is that you can not simply copy text to the clipboard, but rather create a placeholder object. You will not be able to use a simple interface like pyperclip, and likely tkinter.
On the bright side, the above example hopefully shows you that PyQt5 is not too complex for a simple application (and definitely a good choice for the non-simple kind). It is also nice that most operating systems support some form of delayed rendering in some form that Qt can latch on to.
Keep in mind that delayed rendering only lets you know when an object is read from the clipboard by some application, not necessarily the one you want. In fact it doesn't have to be a "paste": the application could just be peeking into the clipboard. For the simple operation described in the question, this will likely be fine. If you want better control over the communication, use something more advanced, like OS-specific monitoring of who reads the copied data, or a more robust solution like shared memory.
Disclaimer: I am not an expert in clipboards. This answer is my understanding how they work. It can be totally wrong.
Hardly there is a platform specific way to solve this, let alone do it in a cross-platform way. The act of pasting from a clipboard consists of two disconnected steps:
Peek at/read the clipboard contents
Use that data in an application specific way
During the second step the application may check the type of the data read from the clipboard and may ignore it if doesn't match the type of the data that can be pasted in the active context (e.g. an image cannot be pasted in a plain text editor). If pasting happens, it happens in the user space and each application may do it differently. Detecting all possible implementations under all platforms simply doesn't makes any sense.
At best you can monitor the acts of peeking at the clipboard contents, yet any application (consider a third party clipboard manager) can examine the clipboard eagerly without any explicit actions from the user, hence those events are not necessarily followed by any observable utilization of that data.
The following loose analogy from the real world will probably convince you to abandon looking for a solution. Suppose that you apply for and are granted a patent to some recipe. The patent is published and can be read by anyone. Could you ask for an effective way to detect any instances of a dish being cooked according to the patented recipe?
On ms-windows, it seems you should be able to use a global hook (using SetWindowsHookExA) to intercept the relevant WM_PASTE message.
Well,I used to use this to make a global hotkeys for my tools.(In pynput official document,it also support linux/mac OS.)
A minimal example:
from pynput.keyboard import GlobalHotKeys
import platform
# platform.system() can detect the device.(macOS/Windows/Linux)
def yourfunction():
print("detect paste...") # each time when you pressed "Ctrl+V",it will call the function
if platform.system() == 'Windows':
with GlobalHotKeys({"<ctrl>+v":yourfunction}) as listener:
listener.join()
PS:It could used in Chrome,Edge(Most of application).But it couldn't used in games.
So because I have the unity-gtk-module installed, all gtk-applications export their menu over the dbus SessionBus. My goal is to extract a list of all available menu entries. I've already implemented this with the help of pydbus, but for some reason, this solution is highly unstable and some applications just flat out crash. The unity-gtk-module uses Gio's g_dbus_connection_export_menu_model () to export its GMenuModel modeled menu over dbus, so I thought it would make sense to try to use Gio to process the exported menu. Gio uses the GDBusMenuModel class to retrieve a menu from the bus. Python uses PyGObject for wrapping Gio:
from gi.repository import Gio
connection = Gio.bus_get_sync(Gio.BusType.SESSION, None)
menuModel = Gio.DBusMenuModel.get(connection, [bus-name e.g. ":1.5"], [object-path e.g. "/com/canonical/unity/gtk/window/0"])
Now menuModel should be wrapping the GMenuModel from my application. At this point I'm honestly a bit confused about how exactly the GMenuModel works (the Description is not really helping) but it seems I have to use a GMenuAttributeIter object to iterate through the entries. But when I try this:
iter = Gio.MenuModel.iterate_item_attributes(menuModel, 0) #0 is the index of the root node
this happens:
GLib-GIO-CRITICAL **: g_dbus_menu_model_get_item_attributes: assertion 'proxy->items' failed
GLib-GIO-CRITICAL **: GMenuModel implementation 'GDBusMenuModel' doesn't override iterate_item_attributes() and fails to return sane calues from get_item_attributes()
This probably happens because GDBusMenuModel inherits GMenuModel which provides these methods, but is abstract, so GDBusMenuModel should override them, which it doesn't (see link above, it provides just g_dbus_menu_model_get ()). If this is the case, how am I supposed to actually use this class as a proxy? And if it's not, what am I doing wrong?
I justed logged in to SO the first time after a few years and remembered that I've actually found a solution to this question (I think). Honestly, I can't remember what half of these words even mean, but at the time I wrote a script to accomplish the task posed in the title, and as far as I remember, in the end, it worked out: https://gist.github.com/encomiastical/caa0ee955300bc2a40ef55d123b06212
I have a wxPython GUI with a very large grid. I am using similar code to the GridHugeTable.py example from the wxPython demo -- i.e., using PyGridTableBase to make a virtual grid.
I am running into trouble when I try to interactively add columns to this grid, however.
Calling AppendCols(1) results in this error:
wx._core.PyAssertionError: C++ assertion "Assert failure" failed at /Users/vagrant/pisi-64bit/tmp/wxPython-3.0.2.0-3/work/wxPython-src-3.0.2.0/src/generic/grid.cpp(1129) in AppendCols():
Called grid table class function AppendCols but your derived table class does not override this function
But if I try to overwrite AppendCols in my table class, the application just hangs indefinitely and never resolves. It hangs even if there is actually nothing in my custom AppendCols method at all...
class HugeTable(gridlib.PyGridTableBase):
"""
Table class for virtual grid
"""
def __init__(self, log, num_rows, num_cols):
gridlib.PyGridTableBase.__init__(self)
def AppendCols(self, *args):
pass
I've been able to overwrite other methods successfully, (setValue, getValue, getColLabelValue, etc.), so I'm not sure what is different here.
Update:
I returned to this problem after a while away. I no longer get the wx.__core.PyAssertionError. However, I still can't get my custom AppendCols method to work. I can't figure out what to put in AppendCols to make a new column actually show up.
I'm not sure how to look in the source code -- none of the Python documentation seems to have what I'm looking for, so maybe I need to go digging in wxWidgets? The documentation hasn't helped: https://wiki.wxpython.org/wxPyGridTableBase.
The clue I needed is in the the demo code for custom table.
So, this code works (leaving out my custom logic and just including the bare bones):
def AppendCols(self, *args):
msg = gridlib.GridTableMessage(self, # The table
gridlib.GRIDTABLE_NOTIFY_COLS_APPENDED, # what we did to it
1) # how many
self.GetView().ProcessTableMessage(msg)
return True
I have a game I've been working on for awhile. The core is C++, but I'm using Python for scripting and for Attacks/StatusEffects/Items etc.
I've kind of coded myself into a corner where I'm having to use eval to get the behaviout I want. Here's how it's arising:
I have an xml document that I use to spec attacks, like so:
<Attack name="Megiddo Flare" mp="144" accuracy="1.5" targetting="EnemyParty">
<Flags>
<IgnoreElements/>
<Unreflectable/>
<ConstantDamage/>
<LockedTargetting/>
</Flags>
<Components>
<ElementalWeightComponent>
<Element name="Fire" weight="0.5"/>
</ElementalWeightComponent>
<ConstantDamageCalculatorComponent damage="9995" index="DamageCalculatorComponent"/>
</Components>
</Attack>
I parse this file in python, and build my Attacks. Each Attack consist of any number of Components to implement different behaviour. In this Attack's case, I implement a DamageCalculatorComponent, telling python to use the ConstantDamage variant. I implement all these components in my script files. This is all well and good for component types I'm going to use often. There are some attacks where that attack will be the only attack to use that particular Component Variant. Rather then adding the component to my script files, I wanted to be able to specify the Component class in the xml file.
For instance, If I were to implement the classic White Wind attack from Final Fantasy (restores team HP by the amount of HP of the attacker)
<Attack name="White Wind" mp="41" targetting="AnyParty">
<Flags>
<LockedTargetting/>
</Flags>
<Components>
<CustomComponent index="DamageCalculatorComponent">
<![CDATA[
class WhiteWindDamageComponent(DamageCalculatorComponent):
def __init__(self, Owner):
DamageCalculatorComponent.__init__(self, Owner)
def CalculateDamage(self, Action, Mechanics):
Dmg = 0
character = Action.GetUsers().GetFirst()
SM = character.GetComponent("StatManagerComponent")
if (SM != None):
Dmg = -SM.GetCurrentHP()
return Dmg
return WhiteWindDamageComponent(Owner)
]]>
</CustomComponent>
</Components>
</Attack>
I was wondering if there might be a better way to do this? The only other way I can see is too put every possible Component variant definition into my python files, and expand my Component creators to check for the additional variant. Seems abit wasteful for a single use Component. Is there a better/safer alternative to generating types dynamically, or perhaps another solution I'm not seeing?
Thanks in advance
Inline Python is bad because
Your source code files cannot be understood by Python source code editors and you will miss syntax highlighting
All other tools, like pylint, which can be used to lint and validate source code will fail also
Alternative
In element <CustomComponent index="DamageCalculatorComponent">
... add parameter script:
<CustomComponent index="DamageCalculatorComponent" script="damager.py">
Then add file damager.py somewhere along the file system.
Load it as described here: What is an alternative to execfile in Python 3?
In your main game engine code construct the class out of loaded system module like:
damager_class = sys.modules["mymodulename"].my_factory_function()
All Python modules must share some kind of agreed class names / entry point functions.
If you want to have really pluggable architecture, use Python eggs and setup.py entry points
http://wiki.pylonshq.com/display/pylonscookbook/Using+Entry+Points+to+Write+Plugins
Example
https://github.com/miohtama/vvv/blob/master/setup.py