Python Tools - Session 12B
Ring of Fire Particle FX Tool (Part 1)
2020.04.02 - Session 12B
Session Navigation
Overview
Part 1 of the Ring of Fire tool creates an animated particle effect using emitters distributed around a NURBS circle. Users control the number of emitters and radius through a Qt UI. The tool creates nParticle systems connected to emitters placed at each CV (control vertex) of the circle, then parents everything together for unified animation.
Key Concepts
- NURBS circle creation - Create circles with specific normals and section counts
- CV position queries - Get control vertex positions to place emitters
- nParticle systems - Create particle effects and connect them to emitters
- Dynamic connections - Use
connectDynamicto link emitters to particle systems - Parenting hierarchy - Parent emitters under the NURBS circle for unified transforms
Note
This session uses a companion ring_of_fire.ui file created in Qt Designer for the number-of-emitters and radius controls.
Source Code - ring_of_fire_part1.py
"""
#############################################################################
filename ring_of_fire.py
author [author]
course [course]
Brief Description:
Particle FX Tool
To be used in conjunction with "ring_of_fire.ui" - place them next to each other
Session 12B - Apr 2 2020
#############################################################################
"""
import pymel.core as pm
import os
from PySide2 import QtCore
from PySide2 import QtWidgets
from PySide2 import QtUiTools
from shiboken2 import wrapInstance
import maya.OpenMayaUI as omui
pm.newFile(force=True)
def get_maya_window():
"""Return the main Maya window
"""
main_window_ptr = omui.MQtUtil.mainWindow()
return wrapInstance(long(main_window_ptr), QtWidgets.QWidget)
def get_script_dir():
"""Returns the directory where the current script lives
"""
script_file = os.path.abspath(__file__)
return os.path.dirname(script_file)
class RingOfFireUI(QtWidgets.QDialog):
def __init__(self, parent=get_maya_window()):
super(RingOfFireUI, self).__init__(parent)
self.setWindowTitle('Ring of Fire FX')
ui_file_path = os.path.join(get_script_dir(), 'ring_of_fire.ui')
qfile_object = QtCore.QFile(ui_file_path)
qfile_object.open(QtCore.QFile.ReadOnly)
loader = QtUiTools.QUiLoader()
self.ui = loader.load(qfile_object, parentWidget=self)
self.ui.btnCreateFX.clicked.connect(self.create_ring)
qfile_object.close()
self.show()
def create_ring(self):
"""Query UI values and pass them to the creation function
"""
number_of_emitters = self.ui.spnNumberOfEmitters.value()
radius = self.ui.spnRadius.value()
create(number_of_emitters, radius)
def create(emitter_count, hoop_radius):
"""Creates an animated particle FX hoop
"""
print emitter_count, hoop_radius
# Create the NURBS circle, facing sideways
hoop = pm.circle(normal=[1,0,0], radius=hoop_radius, sections=emitter_count)[0]
# Create a single particle effect
fx = pm.nParticle()
# Loop through each CV position
for pos in hoop.getCVs():
print pos
# Create a new emitter at the desired location
new_emitter = pm.emitter(pos=pos)
# Connect the emitter to our particle effect
pm.connectDynamic(fx, emitters=new_emitter)
# Parent the emitter to the circle
pm.parent(new_emitter, hoop)
def run():
"""Checks to see if the UI exists, and closes it
"""
for ui_item in QtWidgets.qApp.allWidgets():
if type(ui_item).__name__ == 'RingOfFireUI':
ui_item.close()
RingOfFireUI()