Python API 2.0 Reference
python/api2/py2BrickShader.py
1 from __future__ import division
2 #-
3 # ===========================================================================
4 # Copyright 2020 Autodesk, Inc. All rights reserved.
5 #
6 # Use of this software is subject to the terms of the Autodesk license
7 # agreement provided at the time of installation or download, or which
8 # otherwise accompanies this software in either electronic or hard copy form.
9 # ===========================================================================
10 #+
11 
12 import sys
13 import math
14 import maya.api.OpenMaya as om
15 import maya.api.OpenMayaRender as omr
16 
17 # Produces dependency graph node brickTexture
18 # This node is an example of a brick 2d texture.
19 # The output attribute of the BrickTexture node is called "outColor". To use this shader, create a BrickTexture
20 # and connect its output to an input of a surface/shader node such as Color.
21 
22 
23 def maya_useNewAPI():
24  """
25  The presence of this function tells Maya that the plugin produces, and
26  expects to be passed, objects created using the Maya Python API 2.0.
27  """
28  pass
29 
30 def step(t, c):
31  if t < c:
32  return 0.0
33  return 1.0
34 
35 def smoothstep(t, a, b):
36  if t < a:
37  return 0.0
38  if t > b:
39  return 1.0
40  t = (t - a)/(b - a)
41  return t*t*(3.0 - 2.0*t)
42 
43 def linearstep(t, a, b):
44  if t < a:
45  return 0.0
46  if t > b:
47  return 1.0
48  return (t - a)/(b - a)
49 
50 ##
51 ## Node declaration
52 #######################################################
53 class brickTextureNode(om.MPxNode):
54  # Id tag for use with binary file format
55  id = om.MTypeId( 0x81163 )
56 
57  # Input attributes
58  aColor1 = None
59  aColor2 = None
60  aBlurFactor = None
61  aUVCoord = None
62  aFilterSize = None
63 
64  # Output attributes
65  aOutColor = None
66 
67  @staticmethod
68  def creator():
69  return brickTextureNode()
70 
71  @staticmethod
72  def initialize():
73  nAttr = om.MFnNumericAttribute()
74 
75  # Input attributes
76 
77  brickTextureNode.aColor1 = nAttr.createColor("brickColor", "bc")
78  nAttr.keyable = True
79  nAttr.storable = True
80  nAttr.readable = True
81  nAttr.writable = True
82  nAttr.default = (.75, .3, .1) # Brown
83 
84  brickTextureNode.aColor2 = nAttr.createColor("jointColor", "jc")
85  nAttr.keyable = True
86  nAttr.storable = True
87  nAttr.readable = True
88  nAttr.writable = True
89  nAttr.default = (.75, .75, .75) # Grey
90 
91  brickTextureNode.aBlurFactor = nAttr.create( "blurFactor", "bf", om.MFnNumericData.kFloat)
92  nAttr.keyable = True
93  nAttr.storable = True
94  nAttr.readable = True
95  nAttr.writable = True
96 
97  # Implicit shading network attributes
98 
99  child1 = nAttr.create( "uCoord", "u", om.MFnNumericData.kFloat)
100  child2 = nAttr.create( "vCoord", "v", om.MFnNumericData.kFloat)
101  brickTextureNode.aUVCoord = nAttr.create( "uvCoord", "uv", child1, child2)
102  nAttr.keyable = True
103  nAttr.storable = True
104  nAttr.readable = True
105  nAttr.writable = True
106  nAttr.hidden = True
107 
108  child1 = nAttr.create( "uvFilterSizeX", "fsx", om.MFnNumericData.kFloat)
109  child2 = nAttr.create( "uvFilterSizeY", "fsy", om.MFnNumericData.kFloat)
110  brickTextureNode.aFilterSize = nAttr.create("uvFilterSize", "fs", child1, child2)
111  nAttr.keyable = True
112  nAttr.storable = True
113  nAttr.readable = True
114  nAttr.writable = True
115  nAttr.hidden = True
116 
117  # Output attributes
118  brickTextureNode.aOutColor = nAttr.createColor("outColor", "oc")
119  nAttr.keyable = False
120  nAttr.storable = False
121  nAttr.readable = True
122  nAttr.writable = False
123 
124  # Add attributes to the node database.
125  om.MPxNode.addAttribute(brickTextureNode.aColor1)
126  om.MPxNode.addAttribute(brickTextureNode.aColor2)
127  om.MPxNode.addAttribute(brickTextureNode.aBlurFactor)
128  om.MPxNode.addAttribute(brickTextureNode.aFilterSize)
129  om.MPxNode.addAttribute(brickTextureNode.aUVCoord)
130 
131  om.MPxNode.addAttribute(brickTextureNode.aOutColor)
132 
133  # All input affect the output color
134  om.MPxNode.attributeAffects(brickTextureNode.aColor1, brickTextureNode.aOutColor)
135  om.MPxNode.attributeAffects(brickTextureNode.aColor2, brickTextureNode.aOutColor)
136  om.MPxNode.attributeAffects(brickTextureNode.aBlurFactor, brickTextureNode.aOutColor)
137  om.MPxNode.attributeAffects(brickTextureNode.aFilterSize, brickTextureNode.aOutColor)
138  om.MPxNode.attributeAffects(brickTextureNode.aUVCoord, brickTextureNode.aOutColor)
139 
140  def __init__(self):
141  om.MPxNode.__init__(self)
142 
143  #######################################################
144  ## DESCRIPTION:
145  ## This function gets called by Maya to evaluate the texture.
146  ##
147  ## Get color1 and color2 from the input block.
148  ## Get UV coordinates from the input block.
149  ## Compute the color of our brick for a given UV coordinate.
150  ## Put the result into the output plug.
151  #######################################################
152  def compute(self, plug, block):
153  # outColor or individial R, G, B channel
154  if (plug != brickTextureNode.aOutColor) and (plug.parent() != brickTextureNode.aOutColor):
155  return None # Let the Maya parent class compute the plug
156 
157  uv = block.inputValue( brickTextureNode.aUVCoord ).asFloat2()
158  surfaceColor1 = block.inputValue( brickTextureNode.aColor1 ).asFloatVector()
159  surfaceColor2 = block.inputValue( brickTextureNode.aColor2 ).asFloatVector()
160 
161  # normalize the UV coords
162  uv[0] -= math.floor(uv[0])
163  uv[1] -= math.floor(uv[1])
164 
165  borderWidth = 0.1
166  brickHeight = 0.4
167  brickWidth = 0.9
168  blur = block.inputValue( brickTextureNode.aBlurFactor ).asFloat()
169 
170  v1 = borderWidth/2
171  v2 = v1 + brickHeight
172  v3 = v2 + borderWidth
173  v4 = v3 + brickHeight
174  u1 = borderWidth/2
175  u2 = brickWidth/2
176  u3 = u2 + borderWidth
177  u4 = u1 + brickWidth
178 
179  fs = block.inputValue( brickTextureNode.aFilterSize ).asFloat2()
180  du = blur*fs[0]/2.0
181  dv = blur*fs[1]/2.0
182 
183  t = max(min(linearstep(uv[1], v1 - dv, v1 + dv) - linearstep(uv[1], v2 - dv, v2 + dv), max(linearstep(uv[0], u3 - du, u3 + du), 1 - linearstep(uv[0], u2 - du, u2 + du))), min(linearstep(uv[1], v3 - dv, v3 + dv) - linearstep(uv[1], v4 - dv, v4 + dv), linearstep(uv[0], u1 - du, u1 + du) - linearstep(uv[0], u4 - du, u4 + du)))
184 
185  resultColor = t*surfaceColor1 + (1.0 - t)*surfaceColor2
186 
187  # set ouput color attribute
188  outColorHandle = block.outputValue( brickTextureNode.aOutColor )
189  outColorHandle.setMFloatVector( resultColor )
190  outColorHandle.setClean()
191 
192  # The plug has been successfully computed
193  return self
194 
195  def postConstructor(self):
196  pass
197 
198 ##
199 ## Override declaration
200 #######################################################
201 class brickTextureNodeOverride(omr.MPxShadingNodeOverride):
202  @staticmethod
203  def creator(obj):
204  return brickTextureNodeOverride(obj)
205 
206  def __init__(self, obj):
207  omr.MPxShadingNodeOverride.__init__(self, obj)
208 
209  # Register fragments with the manager if needed
210  fragmentMgr = omr.MRenderer.getFragmentManager()
211  if fragmentMgr != None:
212  if not fragmentMgr.hasFragment("brickTextureNodePluginFragment"):
213  fragmentBody = "<fragment uiName=\"brickTextureNodePluginFragment\" name=\"brickTextureNodePluginFragment\" type=\"plumbing\" class=\"ShadeFragment\" version=\"1.0\">"
214  fragmentBody += " <description><![CDATA[Brick procedural texture fragment]]></description>"
215  fragmentBody += " <properties>"
216  fragmentBody += " <float3 name=\"brickColor\" />"
217  fragmentBody += " <float3 name=\"jointColor\" />"
218  fragmentBody += " <float name=\"blurFactor\" />"
219  fragmentBody += " <float2 name=\"uvCoord\" semantic=\"mayaUvCoordSemantic\" flags=\"varyingInputParam\" />"
220  fragmentBody += " <float2 name=\"uvFilterSize\" />"
221  fragmentBody += " </properties>"
222  fragmentBody += " <values>"
223  fragmentBody += " <float3 name=\"brickColor\" value=\"0.75,0.3,0.1\" />"
224  fragmentBody += " <float3 name=\"jointColor\" value=\"0.75,0.75,0.75\" />"
225  fragmentBody += " </values>"
226  fragmentBody += " <outputs>"
227  fragmentBody += " <float3 name=\"outColor\" />"
228  fragmentBody += " </outputs>"
229  fragmentBody += " <implementation>"
230  fragmentBody += " <implementation render=\"OGSRenderer\" language=\"Cg\" lang_version=\"2.1\">"
231  fragmentBody += " <function_name val=\"brickTextureNodePluginFragment\" />"
232  fragmentBody += " <source><![CDATA["
233  fragmentBody += "float btnplinearstep(float t, float a, float b) \n"
234  fragmentBody += "{ \n"
235  fragmentBody += " if (t < a) return 0.0f; \n"
236  fragmentBody += " if (t > b) return 1.0f; \n"
237  fragmentBody += " return (t - a)/(b - a); \n"
238  fragmentBody += "} \n"
239  fragmentBody += "float3 brickTextureNodePluginFragment(float3 color1, float3 color2, float blur, float2 uv, float2 fs) \n"
240  fragmentBody += "{ \n"
241  fragmentBody += " uv -= floor(uv); \n"
242  fragmentBody += " float v1 = 0.05f; float v2 = 0.45f; float v3 = 0.55f; float v4 = 0.95f; \n"
243  fragmentBody += " float u1 = 0.05f; float u2 = 0.45f; float u3 = 0.55f; float u4 = 0.95f; \n"
244  fragmentBody += " float du = blur*fs.x/2.0f; \n"
245  fragmentBody += " float dv = blur*fs.y/2.0f; \n"
246  fragmentBody += " float t = max( \n"
247  fragmentBody += " min(btnplinearstep(uv.y, v1 - dv, v1 + dv) - btnplinearstep(uv.y, v2 - dv, v2 + dv), \n"
248  fragmentBody += " max(btnplinearstep(uv.x, u3 - du, u3 + du), 1.0f - btnplinearstep(uv.x, u2 - du, u2 + du))), \n"
249  fragmentBody += " min(btnplinearstep(uv.y, v3 - dv, v3 + dv) - btnplinearstep(uv.y, v4 - dv, v4 + dv), \n"
250  fragmentBody += " btnplinearstep(uv.x, u1 - du, u1 + du) - btnplinearstep(uv.x, u4 - du, u4 + du))); \n"
251  fragmentBody += " return t*color1 + (1.0f - t)*color2; \n"
252  fragmentBody += "} \n]]>"
253  fragmentBody += " </source>"
254  fragmentBody += " </implementation>"
255  fragmentBody += " <implementation render=\"OGSRenderer\" language=\"HLSL\" lang_version=\"11.0\">"
256  fragmentBody += " <function_name val=\"brickTextureNodePluginFragment\" />"
257  fragmentBody += " <source><![CDATA["
258  fragmentBody += "float btnplinearstep(float t, float a, float b) \n"
259  fragmentBody += "{ \n"
260  fragmentBody += " if (t < a) return 0.0f; \n"
261  fragmentBody += " if (t > b) return 1.0f; \n"
262  fragmentBody += " return (t - a)/(b - a); \n"
263  fragmentBody += "} \n"
264  fragmentBody += "float3 brickTextureNodePluginFragment(float3 color1, float3 color2, float blur, float2 uv, float2 fs) \n"
265  fragmentBody += "{ \n"
266  fragmentBody += " uv -= floor(uv); \n"
267  fragmentBody += " float v1 = 0.05f; float v2 = 0.45f; float v3 = 0.55f; float v4 = 0.95f; \n"
268  fragmentBody += " float u1 = 0.05f; float u2 = 0.45f; float u3 = 0.55f; float u4 = 0.95f; \n"
269  fragmentBody += " float du = blur*fs.x/2.0f; \n"
270  fragmentBody += " float dv = blur*fs.y/2.0f; \n"
271  fragmentBody += " float t = max( \n"
272  fragmentBody += " min(btnplinearstep(uv.y, v1 - dv, v1 + dv) - btnplinearstep(uv.y, v2 - dv, v2 + dv), \n"
273  fragmentBody += " max(btnplinearstep(uv.x, u3 - du, u3 + du), 1.0f - btnplinearstep(uv.x, u2 - du, u2 + du))), \n"
274  fragmentBody += " min(btnplinearstep(uv.y, v3 - dv, v3 + dv) - btnplinearstep(uv.y, v4 - dv, v4 + dv), \n"
275  fragmentBody += " btnplinearstep(uv.x, u1 - du, u1 + du) - btnplinearstep(uv.x, u4 - du, u4 + du))); \n"
276  fragmentBody += " return t*color1 + (1.0f - t)*color2; \n"
277  fragmentBody += "} \n]]>"
278  fragmentBody += " </source>"
279  fragmentBody += " </implementation>"
280  fragmentBody += " <implementation render=\"OGSRenderer\" language=\"GLSL\" lang_version=\"3.0\">"
281  fragmentBody += " <function_name val=\"brickTextureNodePluginFragment\" />"
282  fragmentBody += " <source><![CDATA["
283  fragmentBody += "float btnplinearstep(float t, float a, float b) \n"
284  fragmentBody += "{ \n"
285  fragmentBody += " if (t < a) return 0.0f; \n"
286  fragmentBody += " if (t > b) return 1.0f; \n"
287  fragmentBody += " return (t - a)/(b - a); \n"
288  fragmentBody += "} \n"
289  fragmentBody += "vec3 brickTextureNodePluginFragment(vec3 color1, vec3 color2, float blur, vec2 uv, vec2 fs) \n"
290  fragmentBody += "{ \n"
291  fragmentBody += " uv -= floor(uv); \n"
292  fragmentBody += " float v1 = 0.05f; float v2 = 0.45f; float v3 = 0.55f; float v4 = 0.95f; \n"
293  fragmentBody += " float u1 = 0.05f; float u2 = 0.45f; float u3 = 0.55f; float u4 = 0.95f; \n"
294  fragmentBody += " float du = blur*fs.x/2.0f; \n"
295  fragmentBody += " float dv = blur*fs.y/2.0f; \n"
296  fragmentBody += " float t = max( \n"
297  fragmentBody += " min(btnplinearstep(uv.y, v1 - dv, v1 + dv) - btnplinearstep(uv.y, v2 - dv, v2 + dv), \n"
298  fragmentBody += " max(btnplinearstep(uv.x, u3 - du, u3 + du), 1.0f - btnplinearstep(uv.x, u2 - du, u2 + du))), \n"
299  fragmentBody += " min(btnplinearstep(uv.y, v3 - dv, v3 + dv) - btnplinearstep(uv.y, v4 - dv, v4 + dv), \n"
300  fragmentBody += " btnplinearstep(uv.x, u1 - du, u1 + du) - btnplinearstep(uv.x, u4 - du, u4 + du))); \n"
301  fragmentBody += " return t*color1 + (1.0f - t)*color2; \n"
302  fragmentBody += "} \n]]>"
303  fragmentBody += " </source>"
304  fragmentBody += " </implementation>"
305  fragmentBody += " </implementation>"
306  fragmentBody += "</fragment>"
307 
308  fragmentMgr.addShadeFragmentFromBuffer(fragmentBody.encode('utf-8'), False)
309 
310  def supportedDrawAPIs(self):
311  return omr.MRenderer.kOpenGL | omr.MRenderer.kOpenGLCoreProfile | omr.MRenderer.kDirectX11
312 
313  def fragmentName(self):
314  return "brickTextureNodePluginFragment"
315 
316 
317 ##
318 ## Plugin setup
319 #######################################################
320 sRegistrantId = "brickTexturePlugin_py"
321 
322 def initializePlugin(obj):
323  plugin = om.MFnPlugin(obj, "Autodesk", "4.5", "Any")
324  try:
325  userClassify = "texture/2d:drawdb/shader/texture/2d/brickTexture_py"
326  plugin.registerNode("brickTexture_py", brickTextureNode.id, brickTextureNode.creator, brickTextureNode.initialize, om.MPxNode.kDependNode, userClassify)
327  except:
328  sys.stderr.write("Failed to register node\n")
329  raise
330 
331  try:
332  global sRegistrantId
333  omr.MDrawRegistry.registerShadingNodeOverrideCreator("drawdb/shader/texture/2d/brickTexture_py", sRegistrantId, brickTextureNodeOverride.creator)
334  except:
335  sys.stderr.write("Failed to register override\n")
336  raise
337 
338 def uninitializePlugin(obj):
339  plugin = om.MFnPlugin(obj)
340  try:
341  plugin.deregisterNode(brickTextureNode.id)
342  except:
343  sys.stderr.write("Failed to deregister node\n")
344  raise
345 
346  try:
347  global sRegistrantId
348  omr.MDrawRegistry.deregisterShadingNodeOverrideCreator("drawdb/shader/texture/2d/brickTexture_py", sRegistrantId)
349  except:
350  sys.stderr.write("Failed to deregister override\n")
351  raise
352