How can I set vertex colors with the Maya python api, given a number of uv shells? So for each shell within a single mesh assign a random vertex color. At the bottom I have the previous code which is too slow in more dense meshes.
def setColors():
shells = getUvShelList( cmds.ls(sl=1)[0] )
print ( shells )
"""
#3 similar objects combined into one
{0: ['pCube4.map[0]', 'pCube4.map[1]', 'pCube4.map[2]', 'pCube4.map[3]', 'pCube4.map[4]', 'pCube4.map[5]', 'pCube4.map[6]', 'pCube4.map[7]', 'pCube4.map[8]', 'pCube4.map[9]', 'pCube4.map[10]', 'pCube4.map[11]', 'pCube4.map[12]', 'pCube4.map[13]'],
1: ['pCube4.map[14]', 'pCube4.map[15]', 'pCube4.map[16]', 'pCube4.map[17]', 'pCube4.map[18]', 'pCube4.map[19]', 'pCube4.map[20]', 'pCube4.map[21]', 'pCube4.map[22]', 'pCube4.map[23]', 'pCube4.map[24]', 'pCube4.map[25]', 'pCube4.map[26]', 'pCube4.map[27]'],
2: ['pCube4.map[28]', 'pCube4.map[29]', 'pCube4.map[30]', 'pCube4.map[31]', 'pCube4.map[32]', 'pCube4.map[33]', 'pCube4.map[34]', 'pCube4.map[35]', 'pCube4.map[36]', 'pCube4.map[37]', 'pCube4.map[38]', 'pCube4.map[39]', 'pCube4.map[40]', 'pCube4.map[41]']}
"""
selList2 = om2.MGlobal.getActiveSelectionList()
dagPath = selList2.getDagPath(0)
selMesh = om2.MFnMesh(dagPath)
vertList = list(set(selMesh.getVertices()[1]))
lenVertList = len(vertList)
for shell in shells:
selection_shell = shells.get(shell)
r = [random.random() for i in range(3)]
tempColor = om2.MColor([r[0],r[1],r[2]])
vertexColorList = om2.MColorArray(lenVertList, tempColor)
selMesh.setVertexColors(vertexColorList, vertList)
setColors()
My previous code(too slow):
for shell in chunk:
selection_shell = shells.get(shell)
cmds.select(selection_shell)
facesSel = cmds.polyListComponentConversion(fromUV=True, toFace=True)
cmds.select(facesSel)
r = [random.random() for i in range(3)]
cmds.polyColorPerVertex(facesSel,rgb=(r[0], r[1], r[2]), cdo=1 )
cmds.select(deselect=1)
Here's what I ended up doing, creating a random color per element within a mesh. Similar to element ID in 3ds max.
To answer my own question, I had to convert the UV indices to Vertex indices per shell.
import maya.cmds as cmds
import maya.api.OpenMaya as om
from itertools import zip_longest
from itertools import chain
import random
import colorsys
import time
import maya.mel as mel
class colorVariationShell():
def __init__(self):
self.setSelection()
self.setColors()
def setSelection(self):
# Get the currently selected mesh.
self.mSelList = om.MGlobal.getActiveSelectionList()
self.path = self.mSelList.getDagPath(0)
self.fnMesh = om.MFnMesh(self.path)
def get_progress_bar(self,status_text, max_value):
try:
progress_bar = mel.eval("$tmp = $gMainProgressBar")
except RuntimeError:
progress_bar = None
if progress_bar:
cmds.progressBar(
progress_bar,
edit=True,
beginProgress=True,
isInterruptable=False,
status=status_text,
maxValue=max_value
)
return progress_bar
def getUvShellsOnObj(self):
#Get UV Sets
uvSets = self.fnMesh.getUVSetNames()
for uvset in uvSets:
uvShellIds = self.fnMesh.getUvShellsIds(uvset)[1]
polyVertices = self.fnMesh.getVertices()
polyUvs = self.fnMesh.getAssignedUVs(uvset)
shells = {}
vertexGroup = []
list_zip = zip(polyVertices[1], polyUvs[1])
zipped_list = list(list_zip)
main_progress_bar_3 = self.get_progress_bar("Getting UV Shells IDS", len(zipped_list))
for i, n in enumerate(uvShellIds):
if n in shells:
shells[n].append( i )
else:
shells[n] = [ ( i ) ]
cmds.progressBar(main_progress_bar_3, edit=True, step=1)
cmds.progressBar(main_progress_bar_3, edit=True, endProgress=True)
vertsID = []
uvsID = []
main_progress_bar = self.get_progress_bar("Gathering UV and Vertex Info", len(zipped_list))
for zipItem in zipped_list:
vertsID.append(zipItem[0])
uvsID.append(zipItem[1])
cmds.progressBar(main_progress_bar, edit=True, step=1)
cmds.progressBar(main_progress_bar, edit=True, endProgress=True)
vertex_id_from_shell = {}
main_progress_bar_2 = self.get_progress_bar("Passing UV and Vertex data", len(shells))
for shell in shells:
selection_shell = shells.get(shell)
for idx, item in enumerate(selection_shell):
if item in uvsID:
uv_index = uvsID.index(item)
vertex_ids = vertsID[uv_index]
# if the list does not exist, create it
if shell not in vertex_id_from_shell:
vertex_id_from_shell[shell] = []
# append to list
vertex_id_from_shell[shell].append(vertex_ids)
cmds.progressBar(main_progress_bar_2, edit=True, step=1)
cmds.progressBar(main_progress_bar_2, edit=True, endProgress=True)
return shells, vertex_id_from_shell
def setColors(self):
shells, target_vertex_id = self.getUvShellsOnObj()
#ammount of different colors
var = 3
vertexData = {key : [] for key in range(var)}
pool = []
for val in target_vertex_id.values():
if not pool:
pool = list(range(var))
random.shuffle(pool)
vertexData[pool.pop()].extend(val)
main_progress_bar = self.get_progress_bar("Applying Vertex Colors", len(vertexData))
for vertex_idx, selection_vertex in vertexData.items():
vertexIds = selection_vertex
lenVertList = len(vertexIds)
sat_random = random.uniform(0.5, 1)
increment = 1/len(vertexData)
color_hsv = (vertex_idx*increment, sat_random, vertex_idx*increment+1/len(vertexData))
rgb_color = colorsys.hsv_to_rgb(color_hsv[0],color_hsv[1],color_hsv[2])
final_color = om.MColor(rgb_color)
vertexColorList = om.MColorArray(lenVertList, final_color)
#apply the color
self.fnMesh.setVertexColors(vertexColorList, vertexIds)
cmds.progressBar(main_progress_bar, edit=True, step=1)
cmds.polyOptions(colorShadedDisplay=1)
cmds.progressBar(main_progress_bar, edit=True, endProgress=True)
start_time = time.time()
colorVariationShell()
Related
I'm struggling with OpenMaya here.
I want to be able to take transform information from a list of locators and plug these values to particles shapes.
The goal is to use this over 25000 locators, so I can't create a particle system for each instance. I really need to store position and rotation values to the particles themselves.
To do that I started to dive into OpenMaya... (╯°□°)╯︵ ┻━┻
Anyway, the problem I'm facing now is that my scene crashes every time I launch this script and I can't figure out what I did wrong. I think I'm pretty close, but crashing Maya is not considered a victory.
import pymel.core as pm
import maya.OpenMaya as om
import maya.OpenMayaFX as omfx
import random
### A short script to create the scene with bunch of locators with random pos rot
numOfLoc = 5 # this number will eventually be set 25000 when the script will work.
# create locators with random position location(for test)
def create_gazillion_locators(numOfLoc):
for i in range(0, numOfLoc):
# to create variation
tx = random.uniform(-10, 10)
ty = random.uniform(0, 5)
tz = random.uniform(-10, 10)
rx = random.uniform(0, 360)
ry = random.uniform(0, 360)
rz = random.uniform(0, 360)
pm.spaceLocator()
pm.move(tx, ty, tz)
pm.rotate(rx, ry, rz, ws=True)
# Select locators
def select_locators():
pm.select(cl=True)
loc_selection = pm.listRelatives(pm.ls(type = 'locator'), p=True)
pm.select(loc_selection, r=True)
return loc_selection
# delete the locators
def clean_the_scene():
#del locators (for testing purpiose)
sel = select_locators()
if sel is not None:
pm.delete(sel)
clean_the_scene()
create_gazillion_locators(numOfLoc)
### Actual script
# Found this on the internet. it seems to be more neat
class Vector(om.MVector):
def __str__(self):
return '{0}, {1}, {2}'.format(self.x, self.y, self.z)
def __repr__(self):
return '{0}, {1}, {2}'.format(self.x, self.y, self.z)
# OpenMaya treatment
sel = select_locators()
mSel = om.MSelectionList()
om.MGlobal.getActiveSelectionList(mSel)
mSel_iter = om.MItSelectionList(mSel)
mSel_DagPath = om.MDagPath()
# bvariables to store the transform in
pos_array = om.MVectorArray()
rot_array = om.MVectorArray()
mLoc = om.MObject()
# Main loop of selection iterator.
while not mSel_iter.isDone():
# Get list of selected
mSel_iter.getDagPath(mSel_DagPath)
mSel_iter.getDependNode(mLoc)
dep_node_name = om.MFnDependencyNode(mLoc).name()
transl = pm.getAttr('{}.translate'.format(dep_node_name))
rotate = pm.getAttr('{}.rotate'.format(dep_node_name))
print(dep_node_name)
print(Vector(transl[0], transl[1], transl[2]))
print(Vector(rotate[0], rotate[1], rotate[2]))
pos_array.append(Vector(transl[0], transl[1], transl[2]))
rot_array.append(Vector(rotate[0], rotate[1], rotate[2]))
mSel_iter.next()
# Up untill there it seems to work ok.
nparticles_transform, nparticles_shape = pm.nParticle(position = pos_array)
pm.setAttr('nucleus1.gravity', 0.0)
nparticles_shape.computeRotation.set(True)
pm.addAttr(nparticles_shape, ln = 'rotationPP', dt = 'vectorArray')
pm.addAttr(nparticles_shape, ln = 'rotationPP0', dt = 'vectorArray')
pm.particleInstancer(nparticles_shape, name = p_instancer, edit = True, rotation = "rotationPP")
particle_fn = omfx.MFnParticleSystem(nparticles_shape.__apimobject__())
particle_fn.setPerParticleAttribute('rotationPP', rot_array)
particle_fn.setPerParticleAttribute('rotationPP0', rot_array)
I read lots of things, went through the stack and google, I based my script on several other stuff I found/learnt (I listened to the OpenMaya course on Youtube by Chayan Vinayak)... But I've had a hard time understanding the OpenMaya documentation though.
I had a look and there is no need to use any openmaya in this case if you need pymel anyway. I used cmds for the creation of the locators because it is a bit faster, so if execution speed is a problem, try to switch everything to cmds.
And I think there is no need to set the computeRotation because it's only used during simulation.
import pymel.core as pm
import maya.cmds as cmds
import random
numOfLoc = 5000
def c_create_gazillion_locators(num_of_loc):
for i in range(num_of_loc):
tx = random.uniform(-10, 10)
ty = random.uniform(0, 5)
tz = random.uniform(-10, 10)
rx = random.uniform(0, 360)
ry = random.uniform(0, 360)
rz = random.uniform(0, 360)
cmds.spaceLocator()
cmds.move(tx, ty, tz)
cmds.rotate(rx, ry, rz, ws=True)
create_gazillion_locators(numOfLoc)
locs = pm.ls(type="locator")
locs = pm.listRelatives(locs, p=True)
pos = []
rot = []
for loc in locs:
pos.append(loc.translate.get())
rot.append(loc.rotate.get())
nparticles_transform, nparticles_shape = pm.nParticle(position=pos)
pm.setAttr("nucleus1.gravity", 0.0)
pm.addAttr(nparticles_shape, ln="rotationPP", dt="vectorArray")
pm.addAttr(nparticles_shape, ln="rotationPP0", dt="vectorArray")
rpp= pm.Attribute(nparticles_shape+".rotationPP")
rpp0= pm.Attribute(nparticles_shape+".rotationPP0")
rpp.set(rot)
rpp0.set(rot)
I've made a couple of changes to make it work. I didn't check the particle setup though. In fact, the main problem is mixing two different APIs. Either stick to OpenMaya (or even OpenMaya v2.0) or PyMEL.
import pymel.core as pm
import maya.OpenMaya as om
import maya.OpenMayaFX as omfx
import random
### A short script to create the scene with bunch of locators with random pos rot
numOfLoc = 5 # this number will eventually be set 25000 when the script will work.
# create locators with random position location(for test)
def create_gazillion_locators(num_of_loc):
for i in range(num_of_loc):
# to create variation
tx = random.uniform(-10, 10)
ty = random.uniform(0, 5)
tz = random.uniform(-10, 10)
rx = random.uniform(0, 360)
ry = random.uniform(0, 360)
rz = random.uniform(0, 360)
pm.spaceLocator()
pm.move(tx, ty, tz)
pm.rotate(rx, ry, rz, ws=True)
# Select locators
def select_locators():
pm.select(cl=True)
loc_selection = pm.listRelatives(pm.ls(type="locator"), p=True)
pm.select(loc_selection, r=True)
return loc_selection
# delete the locators
def clean_the_scene():
# del locators (for testing purpiose)
sel = select_locators()
if sel is not None:
pm.delete(sel)
clean_the_scene()
create_gazillion_locators(numOfLoc)
### Actual script
# Found this on the internet. it seems to be more neat
class Vector(om.MVector):
def __str__(self):
return "{0}, {1}, {2}".format(self.x, self.y, self.z)
def __repr__(self):
return "{0}, {1}, {2}".format(self.x, self.y, self.z)
# OpenMaya treatment
sel = select_locators()
mSel = om.MSelectionList()
om.MGlobal.getActiveSelectionList(mSel)
mSel_iter = om.MItSelectionList(mSel)
mSel_DagPath = om.MDagPath()
# bvariables to store the transform in
pos_array = []
rot_array = om.MVectorArray()
mLoc = om.MObject()
# Main loop of selection iterator.
while not mSel_iter.isDone():
# Get list of selected
mSel_iter.getDagPath(mSel_DagPath)
mSel_iter.getDependNode(mLoc)
dep_node_name = om.MFnDependencyNode(mLoc).name()
transl = pm.getAttr("{}.translate".format(dep_node_name))
rotate = pm.getAttr("{}.rotate".format(dep_node_name))
print(dep_node_name)
print(Vector(transl[0], transl[1], transl[2]))
print(Vector(rotate[0], rotate[1], rotate[2]))
pos_array.append((transl[0], transl[1], transl[2]))
rot_array.append(Vector(rotate[0], rotate[1], rotate[2]))
mSel_iter.next()
# Up untill there it seems to work ok.
nparticles_transform, nparticles_shape = pm.nParticle(position=pos_array)
pm.setAttr("nucleus1.gravity", 0.0)
nparticles_shape.computeRotation.set(True)
pm.addAttr(nparticles_shape, ln="rotationPP", dt="vectorArray")
pm.addAttr(nparticles_shape, ln="rotationPP0", dt="vectorArray")
# Create an instancer before trying to edit
instancer_node = pm.particleInstancer(nparticles_shape, name="p_instancer")
pm.particleInstancer(
nparticles_shape, name=instancer_node, edit=True, rotation="rotationPP"
)
particle_fn = omfx.MFnParticleSystem(nparticles_shape.__apimobject__())
particle_fn.setPerParticleAttribute("rotationPP", rot_array)
particle_fn.setPerParticleAttribute("rotationPP0", rot_array)
I have created a PyQt5 GUI in my main.py file which is in a main app folder. In the file for the interface, a button initiates a new class called Calculation (in the file entry.py) passing in the values of several inputs on the page and in this class the startCalculation() method is called. In this method, the different variables are passed to methods in imported python files, then the result of those calculation is returned and passed to the next calculation in another python file. These returns are in the form of arrays containing values (for the y axis which is then displayed using numpy and plotly).
When I run the app and click on the button in the main interface, the app starts loading (rainbow animation on Mac) and it says it is not responding. It is not a problem with the class itself as a normal print test works in the startCalculation() method, but the function from the imported file causes this to happen. Also, no errors are given in the terminal.
The following is code in the PyQt interface file (main.py)
from app import entry
def startButton(self):
massaTotale = float(self.lineEdit.text())
dragCoefficient = float(self.lineEdit_5.text())
liftCoefficient = float(self.lineEdit_6.text())
powerAvionics = float(self.lineEdit_3.text())
powerPayload = float(self.lineEdit_4.text())
airSpeed = float(self.lineEdit_8.text())
valoreUnico = float(self.valoreUnicoEdit.text())
engineEfficiency = float(self.lineEdit_9.text())
turbolenceCoeff = float(self.lineEdit_10.text())
dayOfYear = float(self.day_LineEdit.text())
latitude = float(self.latitude_LineEdit.text())
sunsetHourAngle = float(self.sunsetHourAngle_LineEdit.text())
declination = float(self.declination_LineEdit.text())
newCaluclation = entry.Calculation(massaTotale, dragCoefficient, liftCoefficient, powerAvionics, powerPayload, airSpeed, valoreUnico, engineEfficiency, turbolenceCoeff, dayOfYear, latitude, sunsetHourAngle, declination)
newCaluclation.startCalculation()
And this is the code in the class calling the function in the external file
from app.mainFunctions import pLevel
#constructor method
def __init__(self, massaTotale, dragCoefficient, liftCoefficient, powerAvionics, powerPayload, airSpeed, valoreUnico, efficiencyEngine, turbolenceCoeff, dayOfYear, latitude, sunsetHourAngle, declination):
# calculate plevel
self.totM = massaTotale
self.vair = airSpeed
self.cl = liftCoefficient
self.cd = dragCoefficient
self.efficiencyEngine = efficiencyEngine
self.valoreUnico = valoreUnico
self.powerAvionics = powerAvionics
self.powerPayload = powerPayload
self.turbolenceCoeff = turbolenceCoeff
self.day_of_year = dayOfYear
self.latitude = latitude
self.sunset_hour_angle = sunsetHourAngle
self.declination = declination
#starting the calculation
def startCalculation(self):
self.x_values, self.pLevel_values = pLevel.calculate_pLevel(self.valoreUnico, self.cd, self.cl, self.totM)
'''
self.pEngine_values = pEngine.calculate_pEngine(self.x_values, self.pLevel_values, self.efficiencyEngine, self.turbolenceCoeff)
self.pOut_values = pOut.calculate_pOut(self.x_values, self.pEngine_values, self.powerAvionics, self.powerPayload)
self.I_loctime = I_loctime.calculate_I_loctime(self.day_of_year, self.latitude, self.sunset_hour_angle, self.declination)
self.asm_values = area_Solar_Module.calculate_asm(self.x_values, self.pOut_values, self.I_loctime)
'''
The pLevel.py file has the following code in it and should return the array of values to pass to the second function in the entry Calculation class file.
import math
import numpy as np
import plotly as py
import plotly.graph_objs as go
import ipywidgets as widgets
import plotly.io as pio
import sys
sys.dont_write_bytecode = True
py.offline.init_notebook_mode(connected=True)
pio.renderers.default = "browser"
# calculating pLevel
x_values = []
y_values = []
layoutPLevel = go.Layout(
title="pLevel",
yaxis=dict(
title='pLevel'
),
xaxis=dict(
title='Surface Area Wing'
)
)
def calculate_pLevel(valoreUnico, cd, cl, totM):
x_values = []
count = 0
while (count < 5):
x_values.append(count)
count = count + 0.01
y_values = []
iteration = 0
while (iteration < len(x_values)):
x_value = x_values[iteration]
if (x_value == 0):
y_value = 0
y_values.append(y_value)
else:
if (valoreUnico == 0.0):
# nessun dato per valoreUnico dato, utilizza i due valori separati
y_value = firstPart(cd, cl) * math.sqrt(secondPart(x_value, totM))
y_values.append(y_value)
else:
y_value = valoreUnico * \
math.sqrt(secondPart(x_value, totM))
y_values.append(y_value)
iteration = iteration + 1
else:
yNpArray = np.array(y_values)
xNpArray = np.array(x_values)
tracePLevel = go.Scatter(
x=xNpArray,
y=yNpArray,
mode='lines',
name='pLevel',
line=dict(
shape='spline'
)
)
figPLevel = go.Figure(data=[tracePLevel], layout=layoutPLevel)
figPLevel.show()
return x_values, y_values
def firstPart(cd, cl):
return (cd / cl**(3/2))
def secondPart(x_value, totM):
return (2*(totM * 9.81)**3) / (1.225 * x_value)
The structure of the files is as follows:
-app
-- __main__.py
-- entry.py
-- __init__.py
-- mainFunctions
--- pLevel.py
--- __init__.py
The loop for the x_values in the pLevel function was not adding one to the iteration so the loop went on forever. I just did not notice my error.
Instead of being
while (iteration < len(x_values)):
x_value = x_values[iteration]
if (x_value == 0):
y_value = 0
y_values.append(y_value)
It should be
while (iteration < len(x_values)):
x_value = x_values[iteration]
if (x_value == 0):
y_value = 0
y_values.append(y_value)
iteration = iteration+1
I wanted to try out some raycasting with Python in Maya using OpenMaya.MFnMesh.anyIntersection().
I just want to cast a ray from on object downwards and hit a plane, not go any further so I get only one raycasthit and get the translation values from the raycasthit.
I got the code from a video and made it a bit clearer to understand.
For the code to run properly in Maya you need an object that is higher in the Y-axis than a different one, preferably a polyPlane(for example: having a polySphere at position [0, 3, 0] and a polyPlane at position [0, 0, 0], select the polySphere and run the code)
import maya.OpenMaya as OpenMaya
import maya.cmds as cmds
def RayReposition(*args):
direction = (0.0, -1, 0)
sel = cmds.ls(sl = True)
fromPositionRay = cmds.xform(sel[0], query = True, translation = True)
selShape = cmds.listRelatives(shapes = True)
meshes = cmds.ls(geometry = True)
cmds.select(clear = True)
for x in meshes:
if x == selShape[0]:
continue
else:
OpenMaya.MGlobal.selectByName(x)
sList = OpenMaya.MSelectionList()
OpenMaya.MGlobal.getActiveSelectionList(sList)
item = OpenMaya.MDagPath()
sList.getDagPath(0, item)
item.extendToShape()
fnMesh = OpenMaya.MFnMesh(item)
raySource = OpenMaya.MFloatPoint(fromPositionRay[0], fromPositionRay[1], fromPositionRay[2], 1.0)
rayDir = OpenMaya.MFloatVector(direction[0], direction[1], direction[2])
faceIds = None
triIds = None
idsSorted = False
testBothDirections = False
worldSpace = OpenMaya.MSpace.kWorld
maxParam = 999999
accelParams = None
sortHits = True
hitPoints = OpenMaya.MFloatPointArray()
hitRayParams = OpenMaya.MFloatArray()
hitFaces = OpenMaya.MIntArray()
hitTris = None
hitBarys1 = None
hitBarys2 = None
tolerance = 0.0001
hit = fnMesh.anyIntersection(raySource, rayDir, worldSpace, maxParam, testBothDirections, faceIds, triIds, idsSorted, accelParams, tolerance, hitPoints, hitRayParams, hitFaces, hitTris, hitBarys1, hitBarys2)
OpenMaya.MGlobal.clearSelectionList()
firstHit = (hitPoints[0].x, hitPoints[0].y, hitPoints[0].z)
print firstHit
RayReposition()
I expected to get the translation values from the raycasthit but I get the following error:
TypeError: in method 'MFnMesh_anyIntersection', argument 4 of type 'MIntArray const *'
Using the OpenMaya.MFnMesh.allIntersections() function instead works perfectly fine but I get every single hit from the raycast, but I only want the first hit.
Links to the OpenMaya.MFnMesh API:
link: https://help.autodesk.com/view/MAYAUL/2016/ENU/?guid=__py_ref_class_open_maya_1_1_m_fn_mesh_html
The main thing is that anyIntersection is looking for a single intersection it hits first, not multiple. So your out parameters are of the wrong types because they're arrays.
I would also avoid clearing or making new selections in your loop as it would just slow down performance by having to redraw the viewports every time.
Here's a working example that will create a locator on the first mesh it hits:
import maya.OpenMaya as OpenMaya
import maya.cmds as cmds
def RayReposition(*args):
direction = (0.0, -1, 0)
sel = cmds.ls(sl=True)
fromPositionRay = cmds.xform(sel[0], query=True, translation=True)
selShape = cmds.listRelatives(shapes=True)
meshes = cmds.ls(geometry=True)
for x in meshes:
if x == selShape[0]:
continue
else:
sList = OpenMaya.MSelectionList()
sList.add(x)
item = OpenMaya.MDagPath()
sList.getDagPath(0, item)
item.extendToShape()
fnMesh = OpenMaya.MFnMesh(item)
raySource = OpenMaya.MFloatPoint(fromPositionRay[0], fromPositionRay[1], fromPositionRay[2], 1.0)
rayDir = OpenMaya.MFloatVector(direction[0], direction[1], direction[2])
worldSpace = OpenMaya.MSpace.kWorld
maxParam = 999999
testBothDirections = False
faceIds = None
triIds = None
idsSorted = False
accelParams = None
sortHits = True
hitPoints = OpenMaya.MFloatPoint()
hitRayParams = None
hitFaces = None
hitTris = None
hitBarys1 = None
hitBarys2 = None
tolerance = 0.0001
hit = fnMesh.anyIntersection(
raySource, rayDir, faceIds, triIds, idsSorted, worldSpace, maxParam, testBothDirections, accelParams,
hitPoints, hitRayParams, hitFaces, hitTris, hitBarys1, hitBarys2, tolerance)
if hit:
firstHit = (hitPoints.x, hitPoints.y, hitPoints.z)
loc = cmds.spaceLocator()[0]
cmds.xform(loc, ws=True, t=firstHit)
print "Hit on {} at {}".format(x, firstHit)
break
RayReposition()
I find the c++ documentation a bit more clearer of what the method expects for parameters.
I want to use a checkbox to control the ratio multiplied in slider function.
First I try to change the variable directly, but failed.
Then I try to change the dragCommand, but also failed.
How can I control it?
import pymel.core as pm
import math
myRatio = math.sqrt(2) * 0.5
def myPolyBevel(*args):
# called by convert
def convertOn(*args):
#myRatio = math.sqrt(2) * 0.5
myOffsetSlider.dragCommand = myOffsetOn
def convertOff(*args):
#myRatio = 1.0
myOffsetSlider.dragCommand = myOffsetOff
# called by offset
def myOffsetOn(*args):
temp = pm.floatSliderGrp( myOffsetSlider, query = True, value = True ) * myRatio
pm.setAttr( myBevel.name()+".offset", temp )
def myOffsetOff(*args):
temp = pm.floatSliderGrp( myOffsetSlider, query = True, value = True )
pm.setAttr( myBevel.name()+".offset", temp )
# main
if pm.selected():
# add Bevel
newBevel = pm.polyBevel3( pm.selected(), offset = 0.1 * myRatio, segments = 2, smoothingAngle = 30, chamfer = 1 )
myBevel = newBevel[0]
# UI
bevelWindow = pm.window(title = 'Bevel')
bevelLayout = pm.columnLayout()
myConvert = pm.checkBoxGrp( numberOfCheckBoxes = 1, label = '', label1 = 'Convert', value1 = 1, onCommand = convertOn, offCommand = convertOff )
myOffsetSlider = pm.floatSliderGrp( label='Offset', field = True,
minValue = 0.0, maxValue = 5.0,
fieldMinValue = 0.0, fieldMaxValue = 100.0,
value = 0.1, step = 0.001,
dragCommand = myOffsetOn, changeCommand = myOffsetOn )
pm.showWindow()
# Main
mainWindow = pm.window(title = 'Star')
mainLayout = pm.gridLayout( cellWidthHeight = (40,40), numberOfColumns = 5 )
bevelButton = pm.button( label = 'Bevel', command = myPolyBevel)
pm.showWindow()
You may have to not nest all this command, it makes it harder (or use some Class method)
use partial to pass args :
Maya Python - Using data from UI
here a useful post you can refer, check theodor and my answers on the topic (we often answer this question )
I have displayed the 3D geometry of a model with python and mayavi using spyder successfully.
Now I am faced with a question that I want to click the point of the model to display the information about the point on the scene; NOT just print it.
Is there any way or any functions about it?
Here is the code I have done:
from mayavi import mlab
import meshio
import numpy
def ReadGmshNodes(file,nbcoord):
import scipy
f=open(file,'r')
i=0
goodline=0
nbnodes=0
for l in f:
s=l.split()
if (goodline==1):
if (nbnodes==0):
nbnodes=int(s[0])
nodes=scipy.zeros((nbnodes,nbcoord))
else:
if (i<nbnodes):
if nbcoord==3:
nodes[i,0]=float(s[1])
nodes[i,1]=float(s[2])
nodes[i,2]=float(s[3])
i=i+1
if nbcoord==2:
nodes[i,0]=float(s[1])
nodes[i,1]=float(s[2])
i=i+1
if ( s[0]=='$Nodes' ):
goodline=1
f.close()
return nodes
def ReadGmshDisplacements(file):
import scipy
f=open(file,'r')
i=0
goodline=0
nbnodes=0
j=0
for l in f:
s=l.split()
if (goodline==1):
j=j+1
if (j==8):
nbnodes=int(s[0])
displacements=scipy.zeros((nbnodes,3))
if (j>8):
if (i<nbnodes):
displacements[i,0]=float(s[1])
displacements[i,1]=float(s[2])
displacements[i,2]=float(s[3])
i=i+1
if ( s[0]=='$NodeData' ):
goodline=1
f.close()
return displacements
points, cells, point_data, cell_data, field_data = meshio.read("Wing.msh")
x=points[:,0]
y=points[:,1]
z=points[:,2]
s=numpy.zeros(z.size)+1
triangles=cells ['triangle']
InputFile='Wing-results.msh'
nodes=ReadGmshNodes(InputFile,3)
displacements=ReadGmshDisplacements(InputFile)
from traits.api import HasTraits, Range, Instance,Enum,Array, \
on_trait_change
from traitsui.api import View, Item, Group,CheckListEditor
from mayavi.core.api import PipelineBase,Source
from mayavi.core.ui.api import MayaviScene, SceneEditor, \
MlabSceneModel
def applyscalefactor(scalefactor):
t = displacements[:,2]*scalefactor
xdisp=x+displacements[:,0]
ydisp=y+displacements[:,1]
zdisp=z+t
return xdisp,ydisp,zdisp
class MyModel(HasTraits):
scalefactor = Range(0,100,0,)
minvalue = Range(-0.00483,0,-0.00483,)
maxvalue = Range(0,1.58*10**-3,0,)
coordinates = Array('d', (3,), labels=['x', 'y', 'z'], cols=3,
desc='the coordinate of the picked point')
scene = Instance(MlabSceneModel, ())
plot = Instance(PipelineBase)
figure = None;
colorbar = None;
dispCB = displacements[:,2]
clickpoint_glyphs = None ;
glyph_points = None ;
data_src3d = Instance(Source)
choose_axis = Enum('X', 'Y', 'Z')
#on_trait_change('minvalue,maxvalue,scene.activated')
def update_colorbar(self):
if self.colorbar is None:
self.colorbar =self.scene.mlab.colorbar(title='Wing',orientation='vertical', nb_labels=6)
else:
self.colorbar.data_range=[self.minvalue,self.maxvalue]
#on_trait_change('coordinates,scene.activated')
def picker_callback(self,objPicker):
print(objPicker)
#on_trait_change('scalefactor,scene.activated')
def update_plot(self):
x,y,z=applyscalefactor(self.scalefactor)
if self.plot is None:
self.figure=self.scene.mlab.gcf()
self.plot = self.scene.mlab.triangular_mesh(x,y,z,triangles,scalars=self.dispCB,representation='surface')
self.clickpoint_glyphs = self.scene.mlab.points3d(x,y,z,s,colormap="copper",scale_factor=0.001)
self.glyph_points =self.clickpoint_glyphs.glyph.glyph_source.glyph_source.output.points.to_array()
self.figure.on_mouse_pick(self.picker_callback,type='point')
else:
self.plot.mlab_source.set(x=x, y=y, z=z,scale_factor=0.001,scalars=self.dispCB)
self.update_colorbar()
view = View(Item('scene', editor=SceneEditor(scene_class=MayaviScene),
height=250, width=300, show_label=False),
Group(
'_', 'scalefactor','minvalue','maxvalue'
),
Group(Item('coordinates'),Item('choose_axis',
style='simple',
editor=CheckListEditor(values='XYZ')),
orientation='vertical'),
scrollable=True,
height=100,
resizable=True,
)
my_model = MyModel()
my_model.configure_traits()