Maya Python updating attributes - python

I have 3 attributes, 2 of which will be used together to determine the value of the 3rd.
Trig Function - The user selects which trig function they want to use. Right now it's just sin and cos
Radians - User enters the radians value for the trig function.
output - This value will be connected to an attribute on a noise texture.
My problem is how do I set this up so that when I change the values of "Trig Function" & "Radians" the output value gets updated?
Example code:
import maya.cmds as cmds
import math
cmds.window(title="Simple UI in Maya", width=300 )
theMasterLayout = cmds.columnLayout()
groupName = "testGrp"
cmds.group(empty=True, name=groupName)
cmds.addAttr(ln="WaveType", at='enum', en="sin:cos")
cmds.addAttr(ln="radians", at='double', min=0, max=10, dv=0.2, k=True)
cmds.addAttr(ln='WaveValue', at='double', dv=0)
if cmds.getAttr(groupName + ".WaveType") == "sin":
wave = math.sin(cmds.getAttr(groupName + ".radians"))
else:
wave = math.cos(cmds.getAttr(groupName + ".radians"))
cmds.setAttr(groupName + ".WaveValue", wave)
# Display the window
cmds.showWindow()

I was able to find a solution to this issue. Basically it's just using expressions. But if anyone knows of an alternative method I would still love to hear it.
import maya.cmds as cmds
groupName = "testGrp"
cmds.group(empty=True, name=groupName)
cmds.addAttr(ln="WaveType", at='enum', en="sin:cos")
cmds.addAttr(ln="radians", at='double', min=0, max=10, dv=0.2, k=True)
cmds.addAttr(ln='WaveValue', at='double', dv=0)
expString = 'if ('+ groupName + '.WaveType == 0){\n'
expString += groupName + '.WaveValue = sin(' + groupName + '.radians);\n}'
expString += '\nelse {\n' + groupName + '.WaveValue = cos(' + groupName + '.radians);\n}'
cmds.expression( s=expString,
o=groupName,
n="WaveResult",
ae=1,
uc=all )

Related

Maya only selects items starting with 1 when using group

I am trying to get maya to select everything based on a name to be put into one group, however, every time I run the function, it selects the first item, then every item beginning with a 1. and then doesnt select anything after that. I've tried getting rid of the * but then it only selects item 1 and nothing else. How do I fix this
def tree(num):
for y in range (25):
TREY=rnd.uniform(23,40)
TREX=rnd.randint(-10,10)
TREZ=rnd.randint(-10,10)
cmds.polyPlatonicSolid(n=pfx+"tree_"+str(num)+"_tree_top_"+str(num))
cmds.move(TREX,TREY,TREZ)
cmds.scale(4.5,4.5,4.5)
cmds.group(pfx+"tree_"+str(num)+"_tree_top_"+str(num)+"*",n=pfx+"top_GRP"+str(num))
tree(1)
I assume the problem is related to how Maya will automatically name new objects upon name clashes. Try this:
import random as rnd
import maya.cmds as cmds
def tree(num):
pfx = "prefix_"
n = str(num)
basename = pfx + "tree_" + n + "_tree_top_"
name = basename + n
groupname = pfx + "top_GRP" + n
for y in range(25):
TREY=rnd.uniform(23, 40)
TREX=rnd.randint(-10, 10)
TREZ=rnd.randint(-10, 10)
cmds.polyPlatonicSolid(n=name)
cmds.move(TREX, TREY, TREZ)
cmds.scale(4.5, 4.5, 4.5)
cmds.group(basename + "*", n=groupname)
tree(1)
However, a perhaps better approach is to store all the newly created objects in a list, rather than depend on name
import random as rnd
import maya.cmds as cmds
def tree(num):
pfx = "prefix_"
n = str(num)
name = pfx + "tree_" + n + "_tree_top_" + n
groupname = pfx + "top_GRP" + n
objs = []
for y in range(25):
TREY=rnd.uniform(23, 40)
TREX=rnd.randint(-10, 10)
TREZ=rnd.randint(-10, 10)
obj = cmds.polyPlatonicSolid(n=name)[0]
cmds.move(TREX, TREY, TREZ, obj)
cmds.scale(4.5, 4.5, 4.5, obj)
objs.append(obj)
cmds.group(objs, n=groupname)
tree(1)
Note that a string array is returned from polyPlatonicSolid(), so to get object you need the first element obj = cmds.polyPlatonicSolid()[0]

Update displayed value everytime ipywidgets are updated

In my notebook i have 7 FloatSlider widgets. I want to have the product of these 7 widgets displayed at all times in a way that, as the user moves the sliders, the value displayed is updated. Currently i am trying to display the product of the SliderWidgets in a Widgets.Text (n), but i am not sure if it is the best solution.
import ipywidgets as widgets
caption = widgets.Label(value='Play around with the variables to see how N changes!')
r = widgets.FloatSlider(value=1,
min=1.0,
max=3.0,
step=0.1,
description="R*")
fp = widgets.FloatSlider(value=1,
min=0.35,
max=1.0,
step=0.05,
description="fp")
ne = widgets.FloatSlider(value=1
min=0.2,
max=3.0,
step=0.1,
description="ne")
fl = widgets.FloatSlider(value=1,
min=1.0,
max=1.3,
step=0.05,
description="fl")
fi = widgets.FloatSlider(value=1,
min=0.5,
max=1.5,
step=0.05,
description="fi")
fc = widgets.FloatSlider(value=0.20,
min=0.10,
max=0.30,
step=0.05,
description="fi",)
l = widgets.FloatSlider(value=60000000.0,
min=5000000.0,
max=1000000000.0,
step=5000000,
description="fi")
n = widgets.Text(
value= str(int(r.value * fp.value * ne.value * fl.value * fi.value * fc.value * l.value)) + " civilizations" ,
description='Estimated N:',
disabled=True)
left_box = VBox([r, fp, ne,fl])
right_box = VBox([ fi,fc,l,n])
HBox([left_box, right_box])
This code that i used displays the widgets, but does not update the widget n automatically. What is the best way for me to do it, that does not involve printing a new value everytime?
You can use an observe and a callback function on value change for each slider
def on_value_change(change):
n.value = str(int(r.value * fp.value * ne.value * fl.value * fi.value * fc.value * l.value)) + " civilizations"
r.observe(on_value_change)
fp.observe(on_value_change)
# ...

Select and zoom features of a layer using PyQgis

I want to select features and to zoom on them and do all these steps using PyQgis.
And I'm able to do both of them separatly but it doesn't seems to work when I try to mix the two of them.
Both of the codes I use for them are from the internet. Here's what I use to select features of a layer :
from qgis.core import *
import qgis.utils
lyrMap = QgsVectorLayer('C:/someplace', 'MapName', 'ogr')
QgsMapLayerRegistry.instance().addMapLayer(lyrMap)
expr = QgsExpression("'Attribute' IS NOT NULL")
it = lyrMap.getFeatures(QgsFeatureRequest(expr))
ids = [i.id() for i in it] #select only the features for which the expression is true
lyrMap.setSelectedFeatures(ids)
And it seems to do the trick as features appear selected on QGis.
In order to zoom the code is much more simple, it's just :
canvas = qgis.utils.iface.mapCanvas()
canvas.zoomToSelected(lyrMap)
But it seems that canvas doesn't consider that there's a selection on lyrMap and simply do nothing. I've tried to do the selection manually in QGis, and then zoom using zoomToSelected, and it worked.
But my objective is to do it without needing to do the selection manually...
Note : I don't think that's the issue, but the attribute I'm doing the selection on is from a join between lyrMap and another layer (I didn't put the code here because I don't think it's linked).
Thanks in advances for answers, clues or anything really :) !
This is working for my plugin. I am using python 2.7 and QGIS 1.8 and 2.0.1.You can use this code after including using vector file and adding it to the registry.
self.rubberBand = None
#create vertex marker for point..older versons..
self.vMarker = None
#add rubberbands
self.crossRb = QgsRubberBand(iface.mapCanvas(),QGis.Line)
self.crossRb.setColor(Qt.black)
def pan(self):
print "pan button clicked!"
x = self.dlg.ui.mTxtX.text()
y = self.dlg.ui.mTxtY.text()
if not x:
return
if not y:
return
print x + "," + y
canvas = self.canvas
currExt = canvas.extent()
canvasCenter = currExt.center()
dx = float(x) - canvasCenter.x()
dy = float(y) - canvasCenter.y()
xMin = currExt.xMinimum() + dx
xMax = currExt.xMaximum() + dx
yMin = currExt.yMinimum() + dy
yMax = currExt.yMaximum() + dy
newRect = QgsRectangle(xMin,yMin,xMax,yMax)
canvas.setExtent(newRect)
pt = QgsPoint(float(x),float(y))
self.zoom(pt)
canvas.refresh()
def zoom(self,point):
canvas = self.canvas
currExt = canvas.extent()
leftPt = QgsPoint(currExt.xMinimum(),point.y())
rightPt = QgsPoint(currExt.xMaximum(),point.y())
topPt = QgsPoint(point.x(),currExt.yMaximum())
bottomPt = QgsPoint(point.x(),currExt.yMinimum())
horizLine = QgsGeometry.fromPolyline( [ leftPt , rightPt ] )
vertLine = QgsGeometry.fromPolyline( [ topPt , bottomPt ] )
self.crossRb.reset(QGis.Line)
self.crossRb.addGeometry(horizLine,None)
self.crossRb.addGeometry(vertLine,None)
if QGis.QGIS_VERSION_INT >= 10900:
rb = self.rubberBand
rb.reset(QGis.Point)
rb.addPoint(point)
else:
self.vMarker = QgsVertexMarker(self.canvas)
self.vMarker.setIconSize(10)
self.vMarker.setCenter(point)
self.vMarker.show()
# wait .5 seconds to simulate a flashing effect
QTimer.singleShot(500,self.resetRubberbands)
def resetRubberbands(self):
print "resetting rubberbands.."
canvas = self.canvas
if QGis.QGIS_VERSION_INT >= 10900:
self.rubberBand.reset()
else:
self.vMarker.hide()
canvas.scene().removeItem(self.vMarker)
self.crossRb.reset()
print "completed resetting.."

How to make PyCollada output multiple meshes to the same scene?

So I am using pyCollada to try to export multiple meshes to the same scene. Alas, whenever I try to do so, I can only see one of the meshes I have loaded in. Am I doing something wrong when I create the file? Each individual mesh renders perfectly if I separate them into their own file, but they fail when I attempt to output them to the same file. I have looked through the API, but the documentation is very limited. Any help would be appreciated.
My code is listed shown below.
# -*- coding: utf-8 -*-
"""
Created on Fri Jun 12 14:43:05 2015
#author: skylion
"""
# -*- coding: utf-8 -*-
"""
Created on Thu Jun 11 11:01:48 2015
#author: danaukes
"""
import sys
import popupcad_deprecated
import popupcad_manufacturing_plugins
import popupcad
from popupcad.filetypes.design import Design
import PySide.QtGui as qg
#Draws Collada stuff
from collada import *
import numpy
geom_index = 0;
def exportBodyToMesh(output):
# csg = output.csg
generic = output.generic_laminate()
# layers = generic.layers()
layerdef = d.return_layer_definition()
layerdef.refreshzvalues()
# layers = layerdef.layers
mesh = Collada()
nodes = []
for layer in layerdef.layers:
shapes = generic.geoms[layer]#TODO Add it in for other shapes
zvalue = layerdef.zvalue[layer]
height = zvalue * 1/ popupcad.internal_argument_scaling
print zvalue
if (len(shapes) == 0) : #In case there are no shapes.
print "No shapes skipping"
continue
print shapes
for s in shapes:
geom = createMeshFromShape(s, height, mesh)
mesh.geometries.append(geom)
effect = material.Effect("effect" + str(geom_index), [], "phone", diffuse=(1,0,0), specular=(0,1,0))
mat = material.Material("material" + str(geom_index), "mymaterial", effect)
matnode = scene.MaterialNode("materialref" + str(geom_index), mat, inputs=[])
mesh.effects.append(effect)
mesh.materials.append(mat)
geomnode = scene.GeometryNode(geom, [matnode])
node = scene.Node("node" + str(geom_index), children=[geomnode])
nodes.append(node)
print nodes
myscene = scene.Scene("myscene", nodes)
mesh.scenes.append(myscene)
mesh.scene = myscene
# layer_num = layer_num + 1 #Add the layer thicknes instead of simply + 1
filename = str(output) + '.dae'
mesh.write(filename)
#TODO Add handling in case rigid body has already been selected.
print filename + " has been saved"
def createMeshFromShape(s,layer_num, mesh):
s.exteriorpoints()
a = s.triangles3()
vertices = []
global geom_index
for coord in a:
for dec in coord:
vertices.append(dec[0]) #x-axis
vertices.append(dec[1]) #y-axis
vertices.append(layer_num ) #z-axi
#This scales the verticies properly.
vert_floats = [x/popupcad.internal_argument_scaling for x in vertices]
vert_src = source.FloatSource("cubeverts-array" + str(geom_index), numpy.array(vert_floats), ('X', 'Y', 'Z'))
geom = geometry.Geometry(mesh, "geometry" + str(geom_index), "mycube", [vert_src])
input_list = source.InputList()
input_list.addInput(0, 'VERTEX', "#cubeverts-array" + str(geom_index))
indices = numpy.array(range(0,(len(vertices) / 3)));
triset = geom.createTriangleSet(indices, input_list, "materialref")
geom_index += 1
triset.generateNormals()
geom.primitives.append(triset)
return geom
#Start of actual script
print sys.argv
app = qg.QApplication('exporter.py')
d = Design.open()
print "Loading..."
d.reprocessoperations()
operation = d.operations[3] #Identify bodies
for output in operation.output:
exportBodyToMesh(output)
print "All objects printed"
#sys.exit(app.exec_())
Your code to add the geometry to the scene is outside your inner loop. You're only adding the last geometry to the scene, rather than all of them. You should be creating multiple GeometryNode and adding all of them to the Scene.

Creating own .obj exporter for maya

I am creating my own .obj exporter for maya.
When i'm exporting just one mesh my code works just fine but when exporting several meshes / objects it fails to create the complete meshes.
I'm pretty sure that the problem is when i'm getting the
face.getVertices(), face.getUVIndex() and face.normalIndex() and printing them to the file. As i said the first mesh works fine but when it gets to the second mesh the codinates gets all wrong, they connect to the wrong triangles.
If anyone has any ideas on how to possibly loop them differently or change the values to the correct ones i would be forever greatful. Help would be very very appreciated!
Here is an example on how a multi object mesh ends out.
http://postimg.org/image/rr0fvs0v7/
import pymel.core as pm
import pymel.core.nodetypes as nt
planes = pm.ls(sl=True)
def meshFile():
def myRound(n):
return round(n, 6)
file = open("C:/Users/Blondiegirls/Desktop/test2.obj", "wb")
file.write("mtllib test2.mtl\r\n")
for p in planes[:]:
#pm.polyTriangulate(planes[0])
file.write("\r\ng default")
# Printa world kordinater
for index, point in enumerate(p.vtx):
temp = index,map(myRound, point.getPosition(space='world'))
file.write("\r\nv ")
file.write(str(' '.join(map(str, temp[1]))))
# Printa texture kordinater
mesh = pm.ls(g=True)[0]
U,V = mesh.getUVs()
UVs = zip(U,V)
for uv in UVs:
file.write("\r\nvt ")
file.write(str(uv[0])+" "+str(uv[1]))
#printa normals
for n in p.getNormals():
file.write("\r\nvn ")
file.write(str(n[0])+" "+str(n[1])+" "+str(n[2]))
file.write("\r\ns 1")
file.write("\r\ng ")
file.write(str(p))
file.write("\r\nusemtl test")
for faceIndex, face in enumerate(p.faces):
faceVertices = face.getVertices()
faceUV0 = face.getUVIndex(0)+1
faceUV1 = face.getUVIndex(1)+1
faceUV2 = face.getUVIndex(2)+1
faceNor0 = face.normalIndex(0)+1
faceNor1 = face.normalIndex(1)+1
faceNor2 = face.normalIndex(2)+1
file.write("\r\nf ")
faceVertices0 = int(faceVertices[0])+1
faceVertices1 = int(faceVertices[1])+1
faceVertices2 = int(faceVertices[2])+1
temp3 = (str(faceVertices0)) + "/" + (str(faceUV0)) +"/" + (str(faceNor0)) + " " + (str(faceVertices1)) + "/" + (str(faceUV1)) +"/" + (str(faceNor1)) + " " + (str(faceVertices2)) + "/" + (str(faceUV2)) +"/" + (str(faceNor2))
file.write(str(temp3))
file.close()
meshFile()
def MTLFile():
file2 = open("C:/Users/Blondiegirls/Desktop/test2.mtl", "wb")
object = cmds.ls(sl=1)[0].split(':')[0]
#print('object: '+object)
shipTX = pm.PyNode(object)
shadingGroups = shipTX.shadingGroups()
sg1 = shadingGroups[0]
material = sg1.listConnections(source=True, destination=False, type=nt.Lambert)[0]
file = material.color.listConnections(type=nt.File)[0]
filename = file.fileTextureName.get()
materialColor = material.getColor() #for Kd
materialAmbient = material.getAmbientColor() #for Ka
materialSpecular = material.getSpecularColor() #for Ks
refractiveIndex = material.getRefractiveIndex() #for Ni
file2.write("newmtl "+"test"+"\r\n")
file2.write("Ka "+str(materialAmbient[0])+" "+str(materialAmbient[1])+" "+str(materialAmbient[2])+"\r\n")
file2.write("Kd "+str(materialColor[0])+" "+str(materialColor[1])+" "+str(materialColor[2])+"\r\n")
file2.write("Ks "+str(materialSpecular[0])+" "+str(materialSpecular[1])+" "+str(materialSpecular[2])+"\r\n")
file2.write("d 1.0\r\n")
file2.write("Illum 2\r\n")
file2.write("map_Kd "+filename+"\r\n") #for map_Kd
file2.close()
MTLFile()
The problem is this line:
mesh = pm.ls(g=True)[0]
U,V = mesh.getUVs()
This is querying all of the geometry in the scene and returning the first object, but you should be operating on the current mesh in the iteration. I think what you want is:
U,V = p.getUVs()
Also, you should probably consider adding an argument to meshFile() rather than relying on a variable in the global scope.

Categories