Python API 2.0 Reference: scripted/pyDepthShader.py

scripted/pyDepthShader.py
1 from __future__ import division
2 #-
3 # ===========================================================================
4 # Copyright 2015 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 from string import *
13 import maya.api.OpenMaya as om
14 import maya.api.OpenMayaRender as omr
15 import textwrap
16 
17 # Produces dependency graph node DepthShader
18 # This node is an example of a surface shader that colors objects based on the distance from the camera.
19 # The inputs for this node are can be found in the Maya UI on the Attribute Editor for the node.
20 # The output attribute of the node is called "outColor". It is a 3 float value that represents the resulting color produced by the node.
21 # To use this shader, create a DepthShader with Shading Group or connect its output to a Shading Group's "SurfaceShader" attribute.
22 
23 
24 def maya_useNewAPI():
25  """
26  The presence of this function tells Maya that the plugin produces, and
27  expects to be passed, objects created using the Maya Python API 2.0.
28  """
29  pass
30 
31 ##################################################################
32 ## Plugin Depth Shader Class Declaration
33 ##################################################################
34 class depthShader(om.MPxNode):
35  # Id tag for use with binary file format
36  id = om.MTypeId( 0x81002 )
37 
38  # Input attributes
39  aColorNear = None
40  aColorFar = None
41  aNear = None
42  aFar = None
43  aPointCamera = None
44 
45  # Output attributes
46  aOutColor = None
47 
48  @staticmethod
49  def creator():
50  return depthShader()
51 
52  @staticmethod
53  def initialize():
54  nAttr = om.MFnNumericAttribute()
55 
56  # Create input attributes
57 
58  depthShader.aColorNear = nAttr.createColor("color", "c")
59  nAttr.keyable = True
60  nAttr.storable = True
61  nAttr.readable = True
62  nAttr.writable = True
63  nAttr.default = (0.0, 1.0, 0.0) # Green
64 
65 
66  depthShader.aColorFar = nAttr.createColor("colorFar", "cf")
67  nAttr.keyable = True
68  nAttr.storable = True
69  nAttr.readable = True
70  nAttr.writable = True
71  nAttr.default = (0.0, 0.0, 1.0) # Blue
72 
73  depthShader.aNear = nAttr.create("near", "n", om.MFnNumericData.kFloat)
74  nAttr.keyable = True
75  nAttr.storable = True
76  nAttr.readable = True
77  nAttr.writable = True
78  nAttr.setMin(0.0)
79  nAttr.setSoftMax(1000.0)
80 
81  depthShader.aFar = nAttr.create("far", "f", om.MFnNumericData.kFloat)
82  nAttr.keyable = True
83  nAttr.storable = True
84  nAttr.readable = True
85  nAttr.writable = True
86  nAttr.setMin(0.0)
87  nAttr.setSoftMax(1000.0)
88  nAttr.default = 2.0
89 
90  depthShader.aPointCamera = nAttr.createPoint("pointCamera", "p")
91  nAttr.keyable = True
92  nAttr.storable = True
93  nAttr.readable = True
94  nAttr.writable = True
95  nAttr.hidden = True
96 
97  # Create output attributes
98  depthShader.aOutColor = nAttr.createColor("outColor", "oc")
99  nAttr.keyable = False
100  nAttr.storable = False
101  nAttr.readable = True
102  nAttr.writable = False
103 
104  om.MPxNode.addAttribute(depthShader.aColorNear)
105  om.MPxNode.addAttribute(depthShader.aColorFar)
106  om.MPxNode.addAttribute(depthShader.aNear)
107  om.MPxNode.addAttribute(depthShader.aFar)
108  om.MPxNode.addAttribute(depthShader.aPointCamera)
109  om.MPxNode.addAttribute(depthShader.aOutColor)
110 
111  om.MPxNode.attributeAffects(depthShader.aColorNear, depthShader.aOutColor)
112  om.MPxNode.attributeAffects(depthShader.aColorFar, depthShader.aOutColor)
113  om.MPxNode.attributeAffects(depthShader.aNear, depthShader.aOutColor)
114  om.MPxNode.attributeAffects(depthShader.aFar, depthShader.aOutColor)
115  om.MPxNode.attributeAffects(depthShader.aPointCamera, depthShader.aOutColor)
116 
117  def __init__(self):
118  om.MPxNode.__init__(self)
119 
120  def compute(self, plug, block):
121  # outColor or individial R, G, B channel
122  if (plug != depthShader.aOutColor) and (plug.parent() != depthShader.aOutColor):
123  return None # Let the Maya parent class compute the plug
124 
125  # get sample surface shading parameters
126  pCamera = block.inputValue(depthShader.aPointCamera).asFloatVector()
127  cNear = block.inputValue(depthShader.aColorNear).asFloatVector()
128  cFar = block.inputValue(depthShader.aColorFar).asFloatVector()
129  nearClip = block.inputValue(depthShader.aNear).asFloat()
130  farClip = block.inputValue(depthShader.aFar).asFloat()
131 
132  # pCamera.z is negative
133  ratio = 1.0
134  dist = farClip - nearClip
135  if dist != 0:
136  ratio = (farClip + pCamera.z) / dist
137  resultColor = cNear * ratio + cFar*(1.0 - ratio)
138 
139  # set ouput color attribute
140  outColorHandle = block.outputValue( depthShader.aOutColor )
141  outColorHandle.setMFloatVector( resultColor )
142  outColorHandle.setClean()
143 
144  # The plug has been computed successfully
145  return self
146 
147  def postConstructor(self):
148  pass
149 
150 ##################################################################
151 ## Plugin Depth Shader Override Class Declaration
152 ##################################################################
153 class depthShaderOverride(omr.MPxSurfaceShadingNodeOverride):
154  @staticmethod
155  def creator(obj):
156  return depthShaderOverride(obj)
157 
158  def __init__(self, obj):
159  omr.MPxSurfaceShadingNodeOverride.__init__(self, obj)
160 
161  # Register fragments with the manager if needed
162  fragmentMgr = omr.MRenderer.getFragmentManager()
163  if fragmentMgr != None:
164  if not fragmentMgr.hasFragment("depthShaderPluginFragment"):
165  fragmentBody = textwrap.dedent("""
166  <fragment uiName=\"depthShaderPluginFragment\" name=\"depthShaderPluginFragment\" type=\"plumbing\" class=\"ShadeFragment\" version=\"1.0\">
167  <description><![CDATA[Depth shader fragment]]></description>
168  <properties>
169  <float name=\"depthValue\" />
170  <float3 name=\"color\" />
171  <float3 name=\"colorFar\" />
172  <float name=\"near\" />
173  <float name=\"far\" />
174  </properties>
175  <values>
176  <float name=\"depthValue\" value=\"0.0\" />
177  <float3 name=\"color\" value=\"0.0,1.0,0.0\" />
178  <float3 name=\"colorFar\" value=\"0.0,0.0,1.0\" />
179  <float name=\"near\" value=\"0.0\" />
180  <float name=\"far\" value=\"2.0\" />
181  </values>
182  <outputs>
183  <float3 name=\"outColor\" />
184  </outputs>
185  <implementation>
186  <implementation render=\"OGSRenderer\" language=\"Cg\" lang_version=\"2.1\">
187  <function_name val=\"depthShaderPluginFragment\" />
188  <source><![CDATA[
189  float3 depthShaderPluginFragment(float depthValue, float3 cNear, float3 cFar, float nearClip, float farClip) \n
190  { \n
191  float ratio = (farClip + depthValue)/(farClip - nearClip); \n
192  return cNear*ratio + cFar*(1.0f - ratio); \n
193  } \n]]>
194  </source>
195  </implementation>
196  <implementation render=\"OGSRenderer\" language=\"HLSL\" lang_version=\"11.0\">
197  <function_name val=\"depthShaderPluginFragment\" />
198  <source><![CDATA[
199  float3 depthShaderPluginFragment(float depthValue, float3 cNear, float3 cFar, float nearClip, float farClip) \n
200  { \n
201  float ratio = (farClip + depthValue)/(farClip - nearClip); \n
202  return cNear*ratio + cFar*(1.0f - ratio); \n
203  } \n]]>
204  </source>
205  </implementation>
206  <implementation render=\"OGSRenderer\" language=\"GLSL\" lang_version=\"3.0\">
207  <function_name val=\"depthShaderPluginFragment\" />
208  <source><![CDATA[
209  vec3 depthShaderPluginFragment(float depthValue, vec3 cNear, vec3 cFar, float nearClip, float farClip) \n
210  { \n
211  float ratio = (farClip + depthValue)/(farClip - nearClip); \n
212  return cNear*ratio + cFar*(1.0f - ratio); \n
213  } \n]]>
214  </source>
215  </implementation>
216  </implementation>
217  </fragment>""")
218 
219  fragmentMgr.addShadeFragmentFromBuffer(fragmentBody.encode('utf-8'), False)
220 
221  if not fragmentMgr.hasFragment("depthShaderPluginInterpolantFragment"):
222  vertexFragmentBody = textwrap.dedent("""
223  <fragment uiName=\"depthShaderPluginInterpolantFragment\" name=\"depthShaderPluginInterpolantFragment\" type=\"interpolant\" class=\"ShadeFragment\" version=\"1.0\">
224  <description><![CDATA[Depth shader vertex fragment]]></description>
225  <properties>
226  <float3 name=\"Pm\" semantic=\"Pm\" flags=\"varyingInputParam\" />
227  <float4x4 name=\"worldViewProj\" semantic=\"worldviewprojection\" />
228  </properties>
229  <values>
230  </values>
231  <outputs>
232  <float name=\"outDepthValue\" ^1s/>
233  </outputs>
234  <implementation>
235  <implementation render=\"OGSRenderer\" language=\"Cg\" lang_version=\"2.1\">
236  <function_name val=\"depthShaderPluginInterpolantFragment\" />
237  <source><![CDATA[
238  float depthShaderPluginInterpolantFragment(float depthValue) \n
239  { \n
240  return depthValue; \n
241  } \n]]>
242  </source>
243  <vertex_source><![CDATA[
244  float idepthShaderPluginInterpolantFragment(float3 Pm, float4x4 worldViewProj) \n
245  { \n
246  float4 pCamera = mul(worldViewProj, float4(Pm, 1.0f)); \n
247  return (pCamera.z - pCamera.w*2.0f); \n
248  } \n]]>
249  </vertex_source>
250  </implementation>
251  <implementation render=\"OGSRenderer\" language=\"HLSL\" lang_version=\"11.0\">
252  <function_name val=\"depthShaderPluginInterpolantFragment\" />
253  <source><![CDATA[
254  float depthShaderPluginInterpolantFragment(float depthValue) \n
255  { \n
256  return depthValue; \n
257  } \n]]>
258  </source>
259  <vertex_source><![CDATA[
260  float idepthShaderPluginInterpolantFragment(float3 Pm, float4x4 worldViewProj) \n
261  { \n
262  float4 pCamera = mul(float4(Pm, 1.0f), worldViewProj); \n
263  return (pCamera.z - pCamera.w*2.0f); \n
264  } \n]]>
265  </vertex_source>
266  </implementation>
267  <implementation render=\"OGSRenderer\" language=\"GLSL\" lang_version=\"3.0\">
268  <function_name val=\"depthShaderPluginInterpolantFragment\" />
269  <source><![CDATA[
270  float depthShaderPluginInterpolantFragment(float depthValue) \n
271  { \n
272  return depthValue; \n
273  } \n]]>
274  </source>
275  <vertex_source><![CDATA[
276  float idepthShaderPluginInterpolantFragment(vec3 Pm, mat4 worldViewProj) \n
277  { \n
278  vec4 pCamera = worldViewProj * vec4(Pm, 1.0f); \n
279  return (pCamera.z - pCamera.w*2.0f); \n
280  } \n]]>
281  </vertex_source>
282  </implementation>
283  </implementation>
284  </fragment>""")
285 
286  # In DirectX, need to specify a semantic for the output of the vertex shader
287  if omr.MRenderer.drawAPI() == omr.MRenderer.kDirectX11:
288  vertexFragmentBody = vertexFragmentBody.replace("^1s", "semantic=\"extraDepth\" ")
289  else:
290  vertexFragmentBody = vertexFragmentBody.replace("^1s", " ")
291 
292  fragmentMgr.addShadeFragmentFromBuffer(vertexFragmentBody.encode('utf-8'), False)
293 
294  if not fragmentMgr.hasFragment("depthShaderPluginGraph"):
295  fragmentGraphBody = textwrap.dedent("""
296  <fragment_graph name=\"depthShaderPluginGraph\" ref=\"depthShaderPluginGraph\" class=\"FragmentGraph\" version=\"1.0\">
297  <fragments>
298  <fragment_ref name=\"depthShaderPluginFragment\" ref=\"depthShaderPluginFragment\" />
299  <fragment_ref name=\"depthShaderPluginInterpolantFragment\" ref=\"depthShaderPluginInterpolantFragment\" />
300  </fragments>
301  <connections>
302  <connect from=\"depthShaderPluginInterpolantFragment.outDepthValue\" to=\"depthShaderPluginFragment.depthValue\" />
303  </connections>
304  <properties>
305  <float3 name=\"Pm\" ref=\"depthShaderPluginInterpolantFragment.Pm\" semantic=\"Pm\" flags=\"varyingInputParam\" />
306  <float4x4 name=\"worldViewProj\" ref=\"depthShaderPluginInterpolantFragment.worldViewProj\" semantic=\"worldviewprojection\" />
307  <float3 name=\"color\" ref=\"depthShaderPluginFragment.color\" />
308  <float3 name=\"colorFar\" ref=\"depthShaderPluginFragment.colorFar\" />
309  <float name=\"near\" ref=\"depthShaderPluginFragment.near\" />
310  <float name=\"far\" ref=\"depthShaderPluginFragment.far\" />
311  </properties>
312  <values>
313  <float3 name=\"color\" value=\"0.0,1.0,0.0\" />
314  <float3 name=\"colorFar\" value=\"0.0,0.0,1.0\" />
315  <float name=\"near\" value=\"0.0\" />
316  <float name=\"far\" value=\"2.0\" />
317  </values>
318  <outputs>
319  <float3 name=\"outColor\" ref=\"depthShaderPluginFragment.outColor\" />
320  </outputs>
321  </fragment_graph>""")
322 
323  fragmentMgr.addFragmentGraphFromBuffer(fragmentGraphBody.encode('utf-8'))
324 
325  def supportedDrawAPIs(self):
326  return omr.MRenderer.kOpenGL | omr.MRenderer.kOpenGLCoreProfile | omr.MRenderer.kDirectX11
327 
328  def fragmentName(self):
329  return "depthShaderPluginGraph"
330 
331 ##
332 ## Plugin setup
333 #######################################################
334 sRegistrantId = "depthShaderPlugin_py"
335 
336 def initializePlugin(obj):
337  plugin = om.MFnPlugin(obj, "Autodesk", "4.5", "Any")
338  try:
339  userClassify = "shader/surface:drawdb/shader/surface/depthShader_py"
340  plugin.registerNode("depthShader_py", depthShader.id, depthShader.creator, depthShader.initialize, om.MPxNode.kDependNode, userClassify)
341  except:
342  sys.stderr.write("Failed to register node\n")
343  raise
344 
345  try:
346  global sRegistrantId
347  omr.MDrawRegistry.registerSurfaceShadingNodeOverrideCreator("drawdb/shader/surface/depthShader_py", sRegistrantId, depthShaderOverride.creator)
348  except:
349  sys.stderr.write("Failed to register override\n")
350  raise
351 
352 def uninitializePlugin(obj):
353  plugin = om.MFnPlugin(obj)
354  try:
355  plugin.deregisterNode(depthShader.id)
356  except:
357  sys.stderr.write("Failed to deregister node\n")
358  raise
359 
360  try:
361  global sRegistrantId
362  omr.MDrawRegistry.deregisterSurfaceShadingNodeOverrideCreator("drawdb/shader/surface/depthShader_py", sRegistrantId)
363  except:
364  sys.stderr.write("Failed to deregister override\n")
365  raise
366