diff options
Diffstat (limited to 'mayaPlug/shaveMayaRenderer.cpp')
| -rw-r--r-- | mayaPlug/shaveMayaRenderer.cpp | 393 |
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); + } +} |