scripted/pyDepthShader.py

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