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 Maya handle this attribute
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  def postConstructor(self):
144  self.setMPSafe(True)
145 
146 ##################################################################
147 ## Plugin Depth Shader Override Class Declaration
148 ##################################################################
149 class depthShaderOverride(omr.MPxSurfaceShadingNodeOverride):
150  @staticmethod
151  def creator(obj):
152  return depthShaderOverride(obj)
153 
154  def __init__(self, obj):
155  omr.MPxSurfaceShadingNodeOverride.__init__(self, obj)
156 
157  # Register fragments with the manager if needed
158  fragmentMgr = omr.MRenderer.getFragmentManager()
159  if fragmentMgr != None:
160  if not fragmentMgr.hasFragment("depthShaderPluginFragment"):
161  fragmentBody = textwrap.dedent("""
162  <fragment uiName=\"depthShaderPluginFragment\" name=\"depthShaderPluginFragment\" type=\"plumbing\" class=\"ShadeFragment\" version=\"1.0\">
163  <description><![CDATA[Depth shader fragment]]></description>
164  <properties>
165  <float name=\"depthValue\" />
166  <float3 name=\"color\" />
167  <float3 name=\"colorFar\" />
168  <float name=\"near\" />
169  <float name=\"far\" />
170  </properties>
171  <values>
172  <float name=\"depthValue\" value=\"0.0\" />
173  <float3 name=\"color\" value=\"0.0,1.0,0.0\" />
174  <float3 name=\"colorFar\" value=\"0.0,0.0,1.0\" />
175  <float name=\"near\" value=\"0.0\" />
176  <float name=\"far\" value=\"2.0\" />
177  </values>
178  <outputs>
179  <float3 name=\"outColor\" />
180  </outputs>
181  <implementation>
182  <implementation render=\"OGSRenderer\" language=\"Cg\" lang_version=\"2.1\">
183  <function_name val=\"depthShaderPluginFragment\" />
184  <source><![CDATA[
185  float3 depthShaderPluginFragment(float depthValue, float3 cNear, float3 cFar, float nearClip, float farClip) \n
186  { \n
187  float ratio = (farClip + depthValue)/(farClip - nearClip); \n
188  return cNear*ratio + cFar*(1.0f - ratio); \n
189  } \n]]>
190  </source>
191  </implementation>
192  <implementation render=\"OGSRenderer\" language=\"HLSL\" lang_version=\"11.0\">
193  <function_name val=\"depthShaderPluginFragment\" />
194  <source><![CDATA[
195  float3 depthShaderPluginFragment(float depthValue, float3 cNear, float3 cFar, float nearClip, float farClip) \n
196  { \n
197  float ratio = (farClip + depthValue)/(farClip - nearClip); \n
198  return cNear*ratio + cFar*(1.0f - ratio); \n
199  } \n]]>
200  </source>
201  </implementation>
202  <implementation render=\"OGSRenderer\" language=\"GLSL\" lang_version=\"3.0\">
203  <function_name val=\"depthShaderPluginFragment\" />
204  <source><![CDATA[
205  vec3 depthShaderPluginFragment(float depthValue, vec3 cNear, vec3 cFar, float nearClip, float farClip) \n
206  { \n
207  float ratio = (farClip + depthValue)/(farClip - nearClip); \n
208  return cNear*ratio + cFar*(1.0f - ratio); \n
209  } \n]]>
210  </source>
211  </implementation>
212  </implementation>
213  </fragment>""")
214 
215  fragmentMgr.addShadeFragmentFromBuffer(fragmentBody, False)
216 
217  if not fragmentMgr.hasFragment("depthShaderPluginInterpolantFragment"):
218  vertexFragmentBody = textwrap.dedent("""
219  <fragment uiName=\"depthShaderPluginInterpolantFragment\" name=\"depthShaderPluginInterpolantFragment\" type=\"interpolant\" class=\"ShadeFragment\" version=\"1.0\">
220  <description><![CDATA[Depth shader vertex fragment]]></description>
221  <properties>
222  <float3 name=\"Pm\" semantic=\"Pm\" flags=\"varyingInputParam\" />
223  <float4x4 name=\"worldViewProj\" semantic=\"worldviewprojection\" />
224  </properties>
225  <values>
226  </values>
227  <outputs>
228  <float name=\"outDepthValue\" ^1s/>
229  </outputs>
230  <implementation>
231  <implementation render=\"OGSRenderer\" language=\"Cg\" lang_version=\"2.1\">
232  <function_name val=\"depthShaderPluginInterpolantFragment\" />
233  <source><![CDATA[
234  float depthShaderPluginInterpolantFragment(float depthValue) \n
235  { \n
236  return depthValue; \n
237  } \n]]>
238  </source>
239  <vertex_source><![CDATA[
240  float idepthShaderPluginInterpolantFragment(float3 Pm, float4x4 worldViewProj) \n
241  { \n
242  float4 pCamera = mul(worldViewProj, float4(Pm, 1.0f)); \n
243  return (pCamera.z - pCamera.w*2.0f); \n
244  } \n]]>
245  </vertex_source>
246  </implementation>
247  <implementation render=\"OGSRenderer\" language=\"HLSL\" lang_version=\"11.0\">
248  <function_name val=\"depthShaderPluginInterpolantFragment\" />
249  <source><![CDATA[
250  float depthShaderPluginInterpolantFragment(float depthValue) \n
251  { \n
252  return depthValue; \n
253  } \n]]>
254  </source>
255  <vertex_source><![CDATA[
256  float idepthShaderPluginInterpolantFragment(float3 Pm, float4x4 worldViewProj) \n
257  { \n
258  float4 pCamera = mul(float4(Pm, 1.0f), worldViewProj); \n
259  return (pCamera.z - pCamera.w*2.0f); \n
260  } \n]]>
261  </vertex_source>
262  </implementation>
263  <implementation render=\"OGSRenderer\" language=\"GLSL\" lang_version=\"3.0\">
264  <function_name val=\"depthShaderPluginInterpolantFragment\" />
265  <source><![CDATA[
266  float depthShaderPluginInterpolantFragment(float depthValue) \n
267  { \n
268  return depthValue; \n
269  } \n]]>
270  </source>
271  <vertex_source><![CDATA[
272  float idepthShaderPluginInterpolantFragment(vec3 Pm, mat4 worldViewProj) \n
273  { \n
274  vec4 pCamera = worldViewProj * vec4(Pm, 1.0f); \n
275  return (pCamera.z - pCamera.w*2.0f); \n
276  } \n]]>
277  </vertex_source>
278  </implementation>
279  </implementation>
280  </fragment>""")
281 
282  # In DirectX, need to specify a semantic for the output of the vertex shader
283  if omr.MRenderer.drawAPI() == omr.MRenderer.kDirectX11:
284  vertexFragmentBody = replace(vertexFragmentBody, "^1s", "semantic=\"extraDepth\" ")
285  else:
286  vertexFragmentBody = replace(vertexFragmentBody, "^1s", " ")
287 
288  fragmentMgr.addShadeFragmentFromBuffer(vertexFragmentBody, False)
289 
290  if not fragmentMgr.hasFragment("depthShaderPluginGraph"):
291  fragmentGraphBody = textwrap.dedent("""
292  <fragment_graph name=\"depthShaderPluginGraph\" ref=\"depthShaderPluginGraph\" class=\"FragmentGraph\" version=\"1.0\">
293  <fragments>
294  <fragment_ref name=\"depthShaderPluginFragment\" ref=\"depthShaderPluginFragment\" />
295  <fragment_ref name=\"depthShaderPluginInterpolantFragment\" ref=\"depthShaderPluginInterpolantFragment\" />
296  </fragments>
297  <connections>
298  <connect from=\"depthShaderPluginInterpolantFragment.outDepthValue\" to=\"depthShaderPluginFragment.depthValue\" />
299  </connections>
300  <properties>
301  <float3 name=\"Pm\" ref=\"depthShaderPluginInterpolantFragment.Pm\" semantic=\"Pm\" flags=\"varyingInputParam\" />
302  <float4x4 name=\"worldViewProj\" ref=\"depthShaderPluginInterpolantFragment.worldViewProj\" semantic=\"worldviewprojection\" />
303  <float3 name=\"color\" ref=\"depthShaderPluginFragment.color\" />
304  <float3 name=\"colorFar\" ref=\"depthShaderPluginFragment.colorFar\" />
305  <float name=\"near\" ref=\"depthShaderPluginFragment.near\" />
306  <float name=\"far\" ref=\"depthShaderPluginFragment.far\" />
307  </properties>
308  <values>
309  <float3 name=\"color\" value=\"0.0,1.0,0.0\" />
310  <float3 name=\"colorFar\" value=\"0.0,0.0,1.0\" />
311  <float name=\"near\" value=\"0.0\" />
312  <float name=\"far\" value=\"2.0\" />
313  </values>
314  <outputs>
315  <float3 name=\"outColor\" ref=\"depthShaderPluginFragment.outColor\" />
316  </outputs>
317  </fragment_graph>""")
318 
319  fragmentMgr.addFragmentGraphFromBuffer(fragmentGraphBody)
320 
321  def supportedDrawAPIs(self):
322  return omr.MRenderer.kOpenGL | omr.MRenderer.kOpenGLCoreProfile | omr.MRenderer.kDirectX11
323 
324  def fragmentName(self):
325  return "depthShaderPluginGraph"
326 
327 ##
328 ## Plugin setup
329 #######################################################
330 sRegistrantId = "depthShaderPlugin"
331 
332 def initializePlugin(obj):
333  plugin = om.MFnPlugin(obj, "Autodesk", "4.5", "Any")
334  try:
335  userClassify = "shader/surface:drawdb/shader/surface/depthShader"
336  plugin.registerNode("depthShader", depthShader.id, depthShader.creator, depthShader.initialize, om.MPxNode.kDependNode, userClassify)
337  except:
338  sys.stderr.write("Failed to register node\n")
339  raise
340 
341  try:
342  global sRegistrantId
343  omr.MDrawRegistry.registerSurfaceShadingNodeOverrideCreator("drawdb/shader/surface/depthShader", sRegistrantId, depthShaderOverride.creator)
344  except:
345  sys.stderr.write("Failed to register override\n")
346  raise
347 
348 def uninitializePlugin(obj):
349  plugin = om.MFnPlugin(obj)
350  try:
351  plugin.deregisterNode(depthShader.id)
352  except:
353  sys.stderr.write("Failed to deregister node\n")
354  raise
355 
356  try:
357  global sRegistrantId
358  omr.MDrawRegistry.deregisterSurfaceShadingNodeOverrideCreator("drawdb/shader/surface/depthShader", sRegistrantId)
359  except:
360  sys.stderr.write("Failed to deregister override\n")
361  raise
362