aboutsummaryrefslogtreecommitdiff
path: root/mayaPlug/shaveMayaRenderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mayaPlug/shaveMayaRenderer.cpp')
-rw-r--r--mayaPlug/shaveMayaRenderer.cpp393
1 files changed, 393 insertions, 0 deletions
diff --git a/mayaPlug/shaveMayaRenderer.cpp b/mayaPlug/shaveMayaRenderer.cpp
new file mode 100644
index 0000000..1ea2a8c
--- /dev/null
+++ b/mayaPlug/shaveMayaRenderer.cpp
@@ -0,0 +1,393 @@
+// Shave and a Haircut
+// (c) 2019 Epic Games
+// US Patent 6720962
+
+#include <maya/MAnimControl.h>
+#include <maya/MFnDependencyNode.h>
+#include <maya/MGlobal.h>
+#include <maya/MItDependencyNodes.h>
+#include <maya/MString.h>
+#include <maya/MTypeId.h>
+
+#include "shaveConstant.h"
+#include "shaveGlobals.h"
+#include "shaveHairShape.h"
+#include "shaveMaya.h"
+#include "shaveMayaRenderer.h"
+#include "shaveRenderCallback.h"
+#include "shaveUtil.h"
+#include "shaveVertexShader.h"
+
+
+shaveMayaRenderer::shaveMayaRenderer()
+: mHaveVolumeShader(false)
+, mRenderCallback(NULL)
+, mRenderCamera("")
+, mTimeState(shaveMayaRenderer::kAwaitingNothing)
+, mWarningGivenUnsupportedHairMode(false)
+, mWarningGivenUnsupportedInstanceMode(false)
+{
+}
+
+
+shaveMayaRenderer::~shaveMayaRenderer()
+{}
+
+
+void shaveMayaRenderer::frameStart(const shaveGlobals::Globals& g)
+{
+ shaveRenderer::frameStart(g);
+
+ //
+ // We only need the volume shader if we're doing 3D compositing or handling
+ // reflections/refractions for non-geometry hair.
+ //
+ mHaveVolumeShader = false;
+
+ if ((g.doCompositing && !g.composite2d)
+ || (g.visibleInReflections && (mNonGeometryNodes.length() > 0)))
+ {
+ //
+ // If the render camera has changed, remove the volume shader from
+ // the old one and add it to the new one.
+ //
+ MString cameraName;
+ MGlobal::executeCommand("shave_getRenderCamera()", cameraName);
+
+ if (cameraName != mRenderCamera)
+ {
+ MGlobal::executeCommand("shave_cleanupVolumeShader ");
+
+ MGlobal::executeCommand(
+ MString("shave_setupVolumeShader ") + cameraName
+ );
+
+ mHaveVolumeShader = true;
+ mRenderCamera = cameraName;
+ }
+ }
+
+ //
+ // At the moment, the Maya renderer will have us in the center of the
+ // frame to rendered. If motion blur is off, that's great. But if
+ // motion blur is on, we only care about the shutter open and close
+ // times. So we'll have to wait for them.
+ //
+ if (shaveMaya::doMotionBlur)
+ mTimeState = kAwaitingShutterOpen;
+ else
+ {
+ MTime curTime = MAnimControl::currentTime();
+
+ doShutter(curTime, shaveConstant::kShutterBoth);
+ mTimeState = kAwaitingNothing;
+ }
+}
+
+
+void shaveMayaRenderer::frameEnd(const shaveGlobals::Globals& g)
+{
+ mRenderCallback->disableCamRender();
+ shaveRenderer::frameEnd(g);
+}
+
+
+float shaveMayaRenderer::getPixelAspect() const
+{
+ return shaveRenderer::getPixelAspect();
+}
+
+
+shaveConstant::RenderMode shaveMayaRenderer::getBaseRenderMode(bool* renderInstances)
+ const
+{
+ //
+ // Let the base class do its stuff first.
+ //
+ shaveConstant::RenderMode hairRenderMode;
+
+ hairRenderMode = shaveRenderer::getBaseRenderMode(renderInstances);
+
+ //
+ // The base class will have verified that the render modes are valid
+ // for *some* renderer, but we must make sure that they're valid for
+ // *this* renderer.
+ //
+ switch (hairRenderMode)
+ {
+ case shaveConstant::kNoRender:
+ case shaveConstant::kBufferRender:
+ case shaveConstant::kGeometryRender:
+ break;
+
+ default:
+ if(!shaveRender::rendererIsPrMan())//not clear why for rendermane we do not have separate renderer class - dub|22Jun2012
+ {
+ if (!mWarningGivenUnsupportedHairMode)
+ {
+ MGlobal::displayWarning(
+ MString("Shave: The Maya renderer does not support ")
+ + shaveRender::getRenderModeName(hairRenderMode)
+ + " hair render mode. We'll use "
+ + shaveRender::getRenderModeName(shaveConstant::kBufferRender)
+ + " render mode instead."
+ );
+ mWarningGivenUnsupportedHairMode = true;
+ }
+ }
+ hairRenderMode = shaveConstant::kBufferRender;
+ break;
+ }
+
+ //
+ // Return the render mode to the caller.
+ //
+ return hairRenderMode;
+}
+
+
+//
+// Is this node "rendered" using normal Maya geometry?
+//
+bool shaveMayaRenderer::isGeomNode(const shaveHairShape* nodePtr) const
+{
+ //
+ // Instances in Maya are always rendered using normal geometry,
+ // so if instances are being rendered then this one will.
+ //
+ if (nodePtr->isInstanced()) return true;
+
+ //
+ // If the render mode is kGeometryRender then this node will be
+ // rendered using Maya geometry, otherwise it will not.
+ //
+ shaveConstant::RenderMode hairRenderMode = getRenderMode();
+
+ return (hairRenderMode == shaveConstant::kGeometryRender);
+}
+
+
+bool shaveMayaRenderer::needVertexColours() const
+{
+ //
+ // If there are any vertex shaders in the scene, then we'll need vertex
+ // colour info.
+ //
+ MItDependencyNodes iter(MFn::kPluginDependNode);
+
+ for (; !iter.isDone(); iter.next())
+ {
+ MObject node = iter.item();
+ MFnDependencyNode nodeFn(node);
+
+ if (nodeFn.typeId() == shaveVertexShader::id) return true;
+ }
+
+ return false;
+}
+
+
+void shaveMayaRenderer::render(
+ float frame, shaveConstant::ShutterState shutter, const MDagPath& camera
+)
+{
+ if (mNonGeometryNodes.length() > 0)
+ {
+ //
+ // If native illumination is on, the camera render will call
+ // SHAVEapply_illuminationWF() which will need to sample the lights
+ // in the scene. Unfortunately, light sampling only works from
+ // within an MRenderCallback. That means that when native
+ // illumination is on we cannot do the camera render here but must
+ // instead do it in shaveRenderCallback.
+ //
+ // But wait, there's more. Our volumetric compositing runs before
+ // shaveRenderCallback is called and it needs the output from the
+ // render. So if volumetric compositing is on then we need to do
+ // the render now, not later.
+ //
+ // That means that we cannot support both native illumination and
+ // volumetric compositing at the same time. So if they're both on
+ // then volumetric compositing wins.
+ //
+ // That just leaves us with the case where native illumination and
+ // volumetric compositing are both off. In that case we can do the
+ // render either here or in the callback. We choose to do it in the
+ // callback because that way we can progressively display tiles in
+ // the Render View as they render.
+ bool doCamRenderNow = (doShaveCompsGlob && !doShaveComp2dGlob);
+
+ shaveRender::bufferRender(
+ shutter, camera, frame, true, true, doCamRenderNow, true
+ );
+
+ if (!doCamRenderNow
+ && ((shutter == shaveConstant::kShutterClose)
+ || (shutter == shaveConstant::kShutterBoth)))
+ {
+ mRenderCallback->enableCamRender(camera);
+ }
+
+ //
+ // Set up shaders on the lights to make them cast shadows for our
+ // hair.
+ //
+ if (((shutter == shaveConstant::kShutterOpen)
+ || (shutter == shaveConstant::kShutterBoth))
+ && (getShadowSource() == shaveConstant::kShaveShadows)
+ && !shaveShadowMatteGlob)
+ {
+ setupShadowShaders();
+ }
+ }
+}
+
+
+void shaveMayaRenderer::renderEnd()
+{
+ if (mHaveVolumeShader)
+ {
+ if (visibleInReflectionsGlob || !doShaveComp2dGlob)
+ MGlobal::executeCommand("shave_cleanupVolumeShader");
+ }
+
+ //
+ // Remove the compositing callback.
+ //
+ if (mRenderCallback)
+ {
+ MRenderCallback::removeCallback(mRenderCallback);
+ delete mRenderCallback;
+ mRenderCallback = NULL;
+ }
+
+ //
+ // Undo the shadow matte setup.
+ //
+ if (shaveShadowMatteGlob
+ && (getRenderMode() == shaveConstant::kBufferRender))
+ {
+ MGlobal::executeCommand("shave_cleanupShadowMatte");
+ }
+
+ //
+ // Reset warning flags so that the next render will get warnings again.
+ //
+ mWarningGivenUnsupportedHairMode= false;
+ mWarningGivenUnsupportedInstanceMode = false;
+
+ shaveRenderer::renderEnd();
+}
+
+
+void shaveMayaRenderer::renderInterrupted()
+{
+ postCompositeCleanup();
+}
+
+
+void shaveMayaRenderer::renderStart()
+{
+ mTimeState = kAwaitingNothing;
+ shaveRenderer::renderStart();
+
+ //
+ // A shadow matte pass is only useful when there is buffered hair in
+ // the scene. If that's the case, and a shadow matte pass has been
+ // requested, then set it up.
+ //
+ if (shaveShadowMatteGlob
+ && (getRenderMode() == shaveConstant::kBufferRender))
+ {
+ MGlobal::executeCommand("shave_setupShadowMatte");
+ }
+
+ //
+ // Set up a render callback to handle compositing buffer renders onto
+ // the final image.
+ //
+ // NOTE: There's a bug in Maya: it will crash if you reuse an
+ // instance of a render callback object. So we have to
+ // allocate a fresh one each time.
+ //
+ mRenderCallback = new shaveRenderCallback(this);
+
+ MRenderCallback::addCallback(mRenderCallback, 255);
+}
+
+
+void shaveMayaRenderer::timeChange(const MTime& newTime)
+{
+ switch (mTimeState)
+ {
+ case kAwaitingShutterOpen:
+ doShutter(newTime, shaveConstant::kShutterOpen);
+
+ if (shaveRenderCancelled)
+ mTimeState = kAwaitingNothing;
+ else
+ mTimeState = kAwaitingCenterFrame;
+ break;
+
+ case kAwaitingCenterFrame:
+ mTimeState = kAwaitingShutterClose;
+ break;
+
+ case kAwaitingShutterClose:
+ doShutter(newTime, shaveConstant::kShutterClose);
+
+ mTimeState = kAwaitingNothing;
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+//************************************************
+//
+// Helper Methods
+//
+//************************************************
+
+void shaveMayaRenderer::postCompositeCleanup()
+{
+ //
+ // Remove any shadow shaders we may have created.
+ //
+ if (!shaveShadowMatteGlob
+ && (getShadowSource() == shaveConstant::kShaveShadows))
+ {
+ MGlobal::executeCommand("shave_disconnectShadowShaders()");
+ }
+
+ //
+ // It's now safe to free up Shave's render buffers.
+ //
+ shaveRender::bufferRenderCleanup();
+}
+
+
+//
+// Hook up shadow handler nodes to the lights.
+//
+void shaveMayaRenderer::setupShadowShaders()
+{
+ unsigned int i;
+ unsigned int numLights = (unsigned int)shaveUtil::globalLightList.size();
+
+
+ for (i = 0; i < numLights; i++)
+ {
+ MDagPath lightPath = shaveUtil::globalLightList[i].path;
+ MString cmd = "shave_connectShadowShader "
+ + lightPath.fullPathName() + " ";
+
+ //
+ // MString supplies a '+=' operator for ints, but not a '+' operator.
+ //
+ cmd += (int)i;
+ MGlobal::executeCommand(cmd);
+ }
+}