aboutsummaryrefslogtreecommitdiff
path: root/mayaPlug/shaveBackgroundShader.cpp
diff options
context:
space:
mode:
authorBen Marsh <[email protected]>2019-10-22 09:07:59 -0400
committerBen Marsh <[email protected]>2019-10-22 09:07:59 -0400
commitbd0027e737c6512397f841c22786274ed74b927f (patch)
treef7ffbdb8f3741bb7f24635616cc189cba5cb865c /mayaPlug/shaveBackgroundShader.cpp
downloadarchived-shave-and-a-haircut-bd0027e737c6512397f841c22786274ed74b927f.tar.xz
archived-shave-and-a-haircut-bd0027e737c6512397f841c22786274ed74b927f.zip
Adding Shave-and-a-Haircut 9.6
Diffstat (limited to 'mayaPlug/shaveBackgroundShader.cpp')
-rw-r--r--mayaPlug/shaveBackgroundShader.cpp585
1 files changed, 585 insertions, 0 deletions
diff --git a/mayaPlug/shaveBackgroundShader.cpp b/mayaPlug/shaveBackgroundShader.cpp
new file mode 100644
index 0000000..ef45b32
--- /dev/null
+++ b/mayaPlug/shaveBackgroundShader.cpp
@@ -0,0 +1,585 @@
+// Shave and a Haircut
+// (c) 2019 Epic Games
+// US Patent 6720962
+
+#include <maya/MDataBlock.h>
+#include <maya/MDataHandle.h>
+#include <maya/MFloatMatrix.h>
+#include <maya/MFloatVector.h>
+#include <maya/MFnCompoundAttribute.h>
+#include <maya/MFnDependencyNode.h>
+#include <maya/MFnMatrixAttribute.h>
+#include <maya/MFnMessageAttribute.h>
+#include <maya/MFnNumericAttribute.h>
+#include <maya/MFnNumericData.h>
+#include <maya/MPlug.h>
+#include <maya/MRenderUtil.h>
+#include <maya/MString.h>
+#include <maya/MTime.h>
+#include <maya/MTypeId.h>
+
+#include "shaveGlobals.h"
+#include "shaveError.h"
+#include "shaveIO.h"
+#include "shaveSDK.h"
+#include "shaveBackgroundShader.h"
+#include "shaveUtil.h"
+
+MTypeId shaveBackgroundShader::id(0x001029A3);
+
+const MString shaveBackgroundShader::nodeTypeName("shaveBackground");
+
+MObject shaveBackgroundShader::aBackgroundSampler;
+MObject shaveBackgroundShader::aIncludeBackfacing;
+
+MObject shaveBackgroundShader::aLightDataArray;
+MObject shaveBackgroundShader::aLightDirection;
+MObject shaveBackgroundShader::aLightIntensity;
+MObject shaveBackgroundShader::aLightAmbient;
+MObject shaveBackgroundShader::aLightDiffuse;
+MObject shaveBackgroundShader::aLightSpecular;
+MObject shaveBackgroundShader::aLightShadowFraction;
+MObject shaveBackgroundShader::aPreShadowIntensity;
+MObject shaveBackgroundShader::aLightBlindData;
+MObject shaveBackgroundShader::aMatrixEyeToWorld;
+MObject shaveBackgroundShader::aNormalCamera;
+MObject shaveBackgroundShader::aObjectId;
+MObject shaveBackgroundShader::aOldShader;
+MObject shaveBackgroundShader::aOutColor;
+MObject shaveBackgroundShader::aOutMatteOpacity;
+MObject shaveBackgroundShader::aOutTransparency;
+
+#ifdef _DEBUG
+MObject shaveBackgroundShader::aPixelCenter;
+MObject shaveBackgroundShader::aPixelCenterX;
+MObject shaveBackgroundShader::aPixelCenterY;
+#endif
+
+MObject shaveBackgroundShader::aPointWorld;
+MObject shaveBackgroundShader::aRayDepth;
+MObject shaveBackgroundShader::aRayDirection;
+MObject shaveBackgroundShader::aRayOrigin;
+
+
+shaveBackgroundShader::shaveBackgroundShader()
+{
+}
+
+
+shaveBackgroundShader::~shaveBackgroundShader()
+{
+}
+
+
+void* shaveBackgroundShader::creator()
+{
+ return new shaveBackgroundShader();
+}
+
+
+
+MStatus shaveBackgroundShader::initialize()
+{
+ MStatus st;
+ MFnCompoundAttribute cAttr;
+ MFnMatrixAttribute aMat;
+ MFnMessageAttribute aMsg;
+ MFnNumericAttribute nAttr;
+
+ //
+ // Renderer-Supplied Input Attributes
+ //
+ aBackgroundSampler = nAttr.createAddr("backgroundSampler", "rtb");
+ nAttr.setHidden(true);
+ nAttr.setStorable(false);
+ addAttribute(aBackgroundSampler);
+
+
+ aLightDirection = nAttr.createPoint("lightDirection", "ld");
+ nAttr.setDefault(1.0f, 1.0f, 1.0f);
+
+
+ aLightIntensity = nAttr.createColor("lightIntensity", "li");
+ nAttr.setDefault(1.0f, 1.0f, 1.0f);
+
+
+ aLightAmbient = nAttr.create(
+ "lightAmbient",
+ "la",
+ MFnNumericData::kBoolean,
+ true
+ );
+
+ aLightDiffuse = nAttr.create(
+ "lightDiffuse",
+ "ldf",
+ MFnNumericData::kBoolean,
+ true
+ );
+
+ aLightSpecular = nAttr.create(
+ "lightSpecular",
+ "ls",
+ MFnNumericData::kBoolean,
+ false
+ );
+
+ aLightShadowFraction = nAttr.create(
+ "lightShadowFraction",
+ "lsf",
+ MFnNumericData::kFloat,
+ 0.5
+ );
+
+ aPreShadowIntensity = nAttr.create(
+ "preShadowIntensity",
+ "psi",
+ MFnNumericData::kFloat,
+ 1.0
+ );
+
+ aLightBlindData = nAttr.createAddr("lightBlindData", "lbd", 0);
+
+ aLightDataArray = cAttr.create("lightDataArray", "ltd");
+ cAttr.addChild(aLightDirection);
+ cAttr.addChild(aLightIntensity);
+ cAttr.addChild(aLightAmbient);
+ cAttr.addChild(aLightDiffuse);
+ cAttr.addChild(aLightSpecular);
+ cAttr.addChild(aLightShadowFraction);
+ cAttr.addChild(aPreShadowIntensity);
+ cAttr.addChild(aLightBlindData);
+ cAttr.setArray(true);
+ cAttr.setHidden(true);
+ nAttr.setStorable(false);
+ addAttribute(aLightDataArray);
+
+
+ aMatrixEyeToWorld = aMat.create(
+ "matrixEyeToWorld",
+ "etw",
+ MFnMatrixAttribute::kFloat
+ );
+ aMat.setHidden(true);
+ aMat.setStorable(false);
+ addAttribute(aMatrixEyeToWorld);
+
+
+ aNormalCamera = nAttr.createPoint("normalCamera", "n");
+ nAttr.setHidden(true);
+ nAttr.setStorable(false);
+ addAttribute(aNormalCamera);
+
+
+ aObjectId = nAttr.createAddr("objectId", "oi");
+ nAttr.setHidden(true);
+ nAttr.setStorable(false);
+ addAttribute(aObjectId);
+
+
+#ifdef _DEBUG
+ aPixelCenterX = nAttr.create(
+ "pixelCenterX", "pcx", MFnNumericData::kFloat
+ );
+
+ aPixelCenterY = nAttr.create(
+ "pixelCenterY", "pcy", MFnNumericData::kFloat
+ );
+ aPixelCenter = nAttr.create(
+ "pixelCenter",
+ "pc",
+ aPixelCenterX,
+ aPixelCenterY
+ );
+ nAttr.setHidden(true);
+ nAttr.setStorable(false);
+ addAttribute(aPixelCenter);
+#endif
+
+
+ aPointWorld = nAttr.createPoint("pointWorld", "pw");
+ nAttr.setHidden(true);
+ nAttr.setStorable(false);
+ addAttribute(aPointWorld);
+
+
+ aRayDepth = nAttr.create("rayDepth", "rd", MFnNumericData::kInt);
+ nAttr.setHidden(true);
+ nAttr.setStorable(false);
+ addAttribute(aRayDepth);
+
+
+ aRayDirection = nAttr.createPoint("rayDirection", "rad");
+ nAttr.setHidden(true);
+ nAttr.setStorable(false);
+ addAttribute(aRayDirection);
+
+
+ aRayOrigin = nAttr.createPoint("rayOrigin", "ro");
+ nAttr.setHidden(true);
+ nAttr.setStorable(false);
+ addAttribute(aRayOrigin);
+
+
+ //
+ // Custom Input Attributes
+ //
+ aIncludeBackfacing = nAttr.create(
+ "includeBackfacing", "ibf", MFnNumericData::kBoolean, 0.0, &st
+ );
+ MChkErr(st, "cannot create 'includeBackfacing' attribute");
+ nAttr.setDefault(true);
+ st = addAttribute(aIncludeBackfacing);
+ MChkErr(st, "cannot add 'includeBackfacing' attribute");
+
+
+ //
+ // Standard Renderer Output Attributes
+ //
+ aOutColor = nAttr.createColor("outColor", "oc");
+ nAttr.setDefault(0.0f, 0.0f, 0.0f);
+ nAttr.setHidden(true);
+ nAttr.setWritable(false);
+ nAttr.setUsedAsColor(true);
+ addAttribute(aOutColor);
+
+
+ aOutMatteOpacity = nAttr.createColor("outMatteOpacity", "omo");
+ nAttr.setDefault(0.0f, 0.0f, 0.0f);
+ nAttr.setHidden(true);
+ nAttr.setWritable(false);
+ nAttr.setUsedAsColor(true);
+ addAttribute(aOutMatteOpacity);
+
+
+ aOutTransparency = nAttr.createColor("outTransparency", "ot");
+ nAttr.setDefault(0.0f, 0.0f, 0.0f);
+ nAttr.setHidden(true);
+ nAttr.setWritable(false);
+ nAttr.setUsedAsColor(true);
+ addAttribute(aOutTransparency);
+
+
+ //
+ // Custom Output Attributes
+ //
+ aOldShader = aMsg.create("oldShader", "oshd");
+ aMsg.setHidden(true);
+ aMsg.setWritable(false);
+ aMsg.setHidden(true);
+ addAttribute(aOldShader);
+
+
+ //
+ // Set up attribute dependencies.
+ //
+ attributeAffects(aIncludeBackfacing, aOutColor);
+ attributeAffects(aBackgroundSampler, aOutColor);
+ attributeAffects(aLightDataArray, aOutColor);
+ attributeAffects(aMatrixEyeToWorld, aOutColor);
+ attributeAffects(aNormalCamera, aOutColor);
+ attributeAffects(aObjectId, aOutColor);
+ attributeAffects(aPointWorld, aOutColor);
+ attributeAffects(aRayDepth, aOutColor);
+ attributeAffects(aRayDirection, aOutColor);
+ attributeAffects(aRayOrigin, aOutColor);
+
+ attributeAffects(aIncludeBackfacing, aOutMatteOpacity);
+ attributeAffects(aBackgroundSampler, aOutMatteOpacity);
+ attributeAffects(aLightDataArray, aOutMatteOpacity);
+ attributeAffects(aMatrixEyeToWorld, aOutMatteOpacity);
+ attributeAffects(aNormalCamera, aOutMatteOpacity);
+ attributeAffects(aObjectId, aOutMatteOpacity);
+ attributeAffects(aPointWorld, aOutMatteOpacity);
+ attributeAffects(aRayDepth, aOutMatteOpacity);
+ attributeAffects(aRayDirection, aOutMatteOpacity);
+ attributeAffects(aRayOrigin, aOutMatteOpacity);
+
+ attributeAffects(aIncludeBackfacing, aOutTransparency);
+ attributeAffects(aBackgroundSampler, aOutTransparency);
+ attributeAffects(aLightDataArray, aOutTransparency);
+ attributeAffects(aMatrixEyeToWorld, aOutTransparency);
+ attributeAffects(aNormalCamera, aOutTransparency);
+ attributeAffects(aObjectId, aOutTransparency);
+ attributeAffects(aPointWorld, aOutTransparency);
+ attributeAffects(aRayDepth, aOutTransparency);
+ attributeAffects(aRayDirection, aOutTransparency);
+ attributeAffects(aRayOrigin, aOutTransparency);
+
+#ifdef _DEBUG
+ attributeAffects(aPixelCenter, aOutColor);
+ attributeAffects(aPixelCenter, aOutMatteOpacity);
+ attributeAffects(aPixelCenter, aOutTransparency);
+#endif
+
+ return MS::kSuccess;
+}
+
+
+void shaveBackgroundShader::postConstructor( )
+{
+// %%% Can we safely do this, given the use of globals by the Shave
+// engine?
+//
+// setMPSafe(true);
+}
+
+
+MStatus shaveBackgroundShader::compute(const MPlug& plug, MDataBlock& datablock)
+{
+ if ((plug == aOutColor) || (plug.parent() == aOutColor)
+ || (plug == aOutMatteOpacity) || (plug.parent() == aOutMatteOpacity)
+ || (plug == aOutTransparency) || (plug.parent() == aOutTransparency))
+ {
+ const MFloatVector& point = datablock
+ .inputValue(aPointWorld)
+ .asFloatVector();
+
+ const MFloatVector& normal = datablock
+ .inputValue(aNormalCamera)
+ .asFloatVector();
+#ifdef _DEBUG
+ float pixelX = datablock.inputValue(aPixelCenterX).asFloat();
+ float pixelY = datablock.inputValue(aPixelCenterY).asFloat();
+#endif
+
+ bool includeBackfacing = datablock.inputValue(aIncludeBackfacing).asBool();
+ MArrayDataHandle lightArray =
+ datablock.inputArrayValue(aLightDataArray);
+
+ unsigned int numAffectingLights = 0;
+ unsigned int numLights = lightArray.elementCount();
+
+ unsigned int i;
+ float lightShadow = 0.0f;
+ float netIllum = 0.0f;
+ float netShadow = 0.0f;
+ float preShadowIntensity;
+ float totalPreShadowIntensity = 0.0f;
+
+ VERT wpoint;
+ wpoint.x = point.x;
+ wpoint.y = point.y;
+ wpoint.z = point.z;
+
+static unsigned int count = 0;
+if (++count == 7453) count = 0;
+
+ for (i = 0; i < numLights; i++)
+ {
+ MDataHandle light = lightArray.inputValue();
+
+ //
+ // If the preShadowIntensity is zero then the light doesn't
+ // even point at us (or we're beyond it's range) in which case
+ // we don't count it.
+ //
+ preShadowIntensity = light.child(aPreShadowIntensity).asFloat();
+
+ if (preShadowIntensity <= 0.0f) continue;
+
+ //
+ // If the normal is facing away from the light then and we're
+ // not including backfacing polys in the matte, then we don't want
+ // to include that light in the calculation. Otherwise,
+ // backfacing polys are considered to be totally shadowed from
+ // the light.
+ //
+ float hairIllum = 1.0f;
+ MFloatVector dir =
+ light.child(aLightDirection).asFloatVector();
+
+ if (dir * normal < 0.04f)
+ {
+ if (includeBackfacing)
+ lightShadow = 1.0f;
+ else
+ continue;
+ }
+ else
+ lightShadow = light.child(aLightShadowFraction).asFloat();
+
+ numAffectingLights++;
+ totalPreShadowIntensity += preShadowIntensity;
+
+ //
+ // If the point is already completely in shadow, then there's
+ // no point in getting Shave's expensive opinion on the matter.
+ //
+ // Similarly, if Shave's shadow density is set to zero, then no
+ // hair shadows will be displayed so once again we don't need
+ // to ask Shave if the point is in shadow.
+ //
+ if ((lightShadow < 1.0f) && (shaveShadowDensityGlob > 0.0))
+ {
+ //
+ // We need to get this light's index in the
+ // globalLightList.
+ //
+ // If the light has a non-zero 'lightBlindData'
+ // attribute value, then that will be its node pointer,
+ // which is unique, so we can use it to look up the
+ // light's index.
+ //
+ int lightIndex = -1;
+ void* blindData = light.child(aLightBlindData).asAddr();
+ if (blindData != 0)
+ lightIndex = shaveUtil::getLightIndex(blindData);
+
+ //
+ // If we didn't find the light through its blind data,
+ // then try finding it based on its direction.
+ //
+ if (lightIndex < 0)
+ {
+ const MFloatMatrix& camToWorld =
+ datablock.inputValue(aMatrixEyeToWorld).asFloatMatrix();
+
+ dir *= camToWorld;
+
+ lightIndex = shaveUtil::getLightIndex(point, dir);
+ }
+
+ if (lightIndex >= 0)
+ {
+ //
+ // How much of the light's illumination gets
+ // through the hair?
+ //
+ // Note that internally Shave creates multiple
+ // sub-lights for some types of lights. They're
+ // not supposed to overlap but sometimes they do,
+ // so we only want the brightest one.
+ //
+ int id;
+ float temp;
+
+ hairIllum = 10000.0f;
+
+ for (id = shaveUtil::globalLightList[lightIndex].minId;
+ id <= shaveUtil::globalLightList[lightIndex].maxId;
+ id++)
+ {
+ temp = SHAVEilluminate_point(wpoint, id);
+ if (temp < hairIllum) hairIllum = temp;
+ }
+
+ hairIllum = hairIllum * shaveShadowDensityGlob
+ + (1.0f - shaveShadowDensityGlob);
+ }
+ }
+
+ //
+ // lightShadow gives the degree to which the point is shadowed
+ // from that light, with 1.0 being fully shadowed and 0.0 being
+ // fully lit.
+ //
+ // So (preShadowIntensity - lightShadow) gives the amount of
+ // illumination from the light which hits the point, after
+ // shadows but before taking hair into account.
+ //
+ float lightIllum = preShadowIntensity - lightShadow;
+
+ //
+ // We multiply that by the amount of illumination that the hair
+ // will let through to get the final illumination of the point.
+ //
+ float finalIllum = lightIllum * hairIllum;
+
+ //
+ // The final amount of shadowing is (preShadowIntensity -
+ // finalIllum).
+ //
+ lightShadow = preShadowIntensity - finalIllum;
+
+ netShadow += lightShadow;
+
+ if (!lightArray.next()) break;
+ }
+
+ if (totalPreShadowIntensity > 0.0f)
+ {
+ netShadow /= totalPreShadowIntensity;
+ netIllum = 1.0f - netShadow;
+ }
+ else
+ netShadow = 0.0f;
+
+#define USE_BG_SAMPLER
+
+#ifdef USE_BG_SAMPLER
+ MFloatVector traceColor(0.0f, 0.0f, 0.0f);
+
+ if (netIllum > 0.0f)
+ {
+ int rayDepth = datablock.inputValue(aRayDepth).asInt();
+ void*& objectId = datablock.inputValue(aObjectId).asAddr();
+ void*& backgroundSampler =
+ datablock.inputValue(aBackgroundSampler).asAddr();
+
+ const MFloatVector& rayDirection =
+ datablock.inputValue(aRayDirection).asFloatVector();
+
+ const MFloatVector& rayOrigin =
+ datablock.inputValue(aRayOrigin).asFloatVector();
+
+ MFloatVector traceTransp;
+
+ MRenderUtil::raytrace(
+ rayOrigin,
+ rayDirection,
+ objectId,
+ backgroundSampler,
+ (short)rayDepth,
+ traceColor,
+ traceTransp,
+ true
+ );
+ }
+#endif
+
+ MFloatVector& outColor = datablock
+ .outputValue(aOutColor)
+ .asFloatVector();
+
+ MFloatVector& outMatteOpacity = datablock
+ .outputValue(aOutMatteOpacity)
+ .asFloatVector();
+
+ MFloatVector& outTransparency = datablock
+ .outputValue(aOutTransparency)
+ .asFloatVector();
+
+#ifdef USE_BG_SAMPLER
+ outColor = traceColor * netIllum;
+#else
+ outColor.x = 0.0;
+ outColor.y = 0.0;
+ outColor.z = 0.0;
+#endif
+
+ outMatteOpacity.x = netShadow;
+ outMatteOpacity.y = netShadow;
+ outMatteOpacity.z = netShadow;
+
+#ifdef USE_BG_SAMPLER
+ outTransparency.x = 0.0f;
+ outTransparency.y = 0.0f;
+ outTransparency.z = 0.0f;
+#else
+ outTransparency.x = netIllum;
+ outTransparency.y = netIllum;
+ outTransparency.z = netIllum;
+#endif
+
+ datablock.setClean(aOutColor);
+ datablock.setClean(aOutMatteOpacity);
+ datablock.setClean(aOutTransparency);
+ }
+ else
+ return MS::kUnknownParameter;
+
+ return MS::kSuccess;
+}
+
+