aboutsummaryrefslogtreecommitdiff
path: root/mayaPlug/shaveShadowFilter.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/shaveShadowFilter.cpp
downloadshave-and-a-haircut-bd0027e737c6512397f841c22786274ed74b927f.tar.xz
shave-and-a-haircut-bd0027e737c6512397f841c22786274ed74b927f.zip
Adding Shave-and-a-Haircut 9.6
Diffstat (limited to 'mayaPlug/shaveShadowFilter.cpp')
-rw-r--r--mayaPlug/shaveShadowFilter.cpp563
1 files changed, 563 insertions, 0 deletions
diff --git a/mayaPlug/shaveShadowFilter.cpp b/mayaPlug/shaveShadowFilter.cpp
new file mode 100644
index 0000000..80688fc
--- /dev/null
+++ b/mayaPlug/shaveShadowFilter.cpp
@@ -0,0 +1,563 @@
+// Shave and a Haircut
+// (c) 2019 Epic Games
+// US Patent 6720962
+
+#include <maya/MArrayDataBuilder.h>
+#include <maya/MArrayDataHandle.h>
+#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/MGlobal.h>
+#include <maya/MPlug.h>
+#include <maya/MRenderUtil.h>
+#include <maya/MString.h>
+#include <maya/MTypeId.h>
+
+#include "shaveGlobals.h"
+#include "shaveIO.h"
+#include "shaveSDK.h"
+#include "shaveShadowFilter.h"
+#include "shaveUtil.h"
+
+MTypeId shaveShadowFilter::id(0x001029BC);
+
+const MString shaveShadowFilter::nodeTypeName("shaveShadowFilter");
+
+MObject shaveShadowFilter::aLightDataArray;
+MObject shaveShadowFilter::aLightDirection;
+MObject shaveShadowFilter::aLightIntensity;
+MObject shaveShadowFilter::aLightAmbient;
+MObject shaveShadowFilter::aLightDiffuse;
+MObject shaveShadowFilter::aLightSpecular;
+MObject shaveShadowFilter::aLightShadowFraction;
+MObject shaveShadowFilter::aPreShadowIntensity;
+MObject shaveShadowFilter::aLightBlindData;
+
+MObject shaveShadowFilter::aLightDataArrayOut;
+MObject shaveShadowFilter::aLightDirectionOut;
+MObject shaveShadowFilter::aLightIntensityOut;
+MObject shaveShadowFilter::aLightAmbientOut;
+MObject shaveShadowFilter::aLightDiffuseOut;
+MObject shaveShadowFilter::aLightSpecularOut;
+MObject shaveShadowFilter::aLightShadowFractionOut;
+MObject shaveShadowFilter::aPreShadowIntensityOut;
+MObject shaveShadowFilter::aLightBlindDataOut;
+
+MObject shaveShadowFilter::aMatrixEyeToWorld;
+MObject shaveShadowFilter::aNormalCamera;
+MObject shaveShadowFilter::aObjectId;
+
+MObject shaveShadowFilter::aPointWorld;
+MObject shaveShadowFilter::aRayDepth;
+MObject shaveShadowFilter::aRayDirection;
+MObject shaveShadowFilter::aRayOrigin;
+
+
+shaveShadowFilter::shaveShadowFilter()
+{
+}
+
+
+shaveShadowFilter::~shaveShadowFilter()
+{
+}
+
+
+void* shaveShadowFilter::creator()
+{
+ return new shaveShadowFilter();
+}
+
+
+
+MStatus shaveShadowFilter::initialize()
+{
+ MStatus st;
+ MFnCompoundAttribute cAttr;
+ MFnMatrixAttribute matAttr;
+ MFnMessageAttribute msgAttr;
+ MFnNumericAttribute nAttr;
+
+ //
+ // Renderer-Supplied Input Attributes
+ //
+ 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.create(
+ "lightBlindData", "lbd", MFnNumericData::kLong, 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 = matAttr.create(
+ "matrixEyeToWorld",
+ "etw",
+ MFnMatrixAttribute::kFloat
+ );
+ matAttr.setHidden(true);
+ matAttr.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);
+
+
+ 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
+ //
+
+
+ //
+ // Standard Renderer Output Attributes
+ //
+
+ //
+ // Custom Output Attributes
+ //
+ aLightDirectionOut = nAttr.createPoint("lightDirectionOut", "ldo", &st);
+ nAttr.setDefault(1.0f, 1.0f, 1.0f);
+ if (!st)
+ {
+ MGlobal::displayError(
+ nodeTypeName + ": cannot create lightDirectionOut attr: "
+ + st.errorString()
+ );
+ return st;
+ }
+
+
+ aLightIntensityOut = nAttr.createColor("lightIntensityOut", "lio", &st);
+ nAttr.setDefault(1.0f, 1.0f, 1.0f);
+ if (!st)
+ {
+ MGlobal::displayError(
+ nodeTypeName + ": cannot create lightIntensityOut attr: "
+ + st.errorString()
+ );
+ return st;
+ }
+
+
+ aLightAmbientOut = nAttr.create(
+ "lightAmbientOut",
+ "lao",
+ MFnNumericData::kBoolean,
+ true,
+ &st
+ );
+ if (!st)
+ {
+ MGlobal::displayError(
+ nodeTypeName + ": cannot create lightAmbientOut attr: "
+ + st.errorString()
+ );
+ return st;
+ }
+
+ aLightDiffuseOut = nAttr.create(
+ "lightDiffuseOut",
+ "ldfo",
+ MFnNumericData::kBoolean,
+ true,
+ &st
+ );
+ if (!st)
+ {
+ MGlobal::displayError(
+ nodeTypeName + ": cannot create lightDiffuseOut attr: "
+ + st.errorString()
+ );
+ return st;
+ }
+
+ aLightSpecularOut = nAttr.create(
+ "lightSpecularOut",
+ "lso",
+ MFnNumericData::kBoolean,
+ false,
+ &st
+ );
+ if (!st)
+ {
+ MGlobal::displayError(
+ nodeTypeName + ": cannot create lightSpecularOut attr: "
+ + st.errorString()
+ );
+ return st;
+ }
+
+ aLightShadowFractionOut = nAttr.create(
+ "lightShadowFractionOut",
+ "lsfo",
+ MFnNumericData::kFloat,
+ 0.5,
+ &st
+ );
+ if (!st)
+ {
+ MGlobal::displayError(
+ nodeTypeName + ": cannot create lightShadowFractionOut attr: "
+ + st.errorString()
+ );
+ return st;
+ }
+
+ aPreShadowIntensityOut = nAttr.create(
+ "preShadowIntensityOut",
+ "psio",
+ MFnNumericData::kFloat,
+ 1.0,
+ &st
+ );
+ if (!st)
+ {
+ MGlobal::displayError(
+ nodeTypeName + ": cannot create preShadowIntensityOut attr: "
+ + st.errorString()
+ );
+ return st;
+ }
+
+ aLightBlindDataOut = nAttr.create(
+ "lightBlindDataOut",
+ "lbdo",
+ MFnNumericData::kLong,
+ 0,
+ &st
+ );
+ if (!st)
+ {
+ MGlobal::displayError(
+ nodeTypeName + ": cannot create lightBlindDataOut attr: "
+ + st.errorString()
+ );
+ return st;
+ }
+
+ aLightDataArrayOut = cAttr.create("lightDataArrayOut", "ltdo", &st);
+ if (!st)
+ {
+ MGlobal::displayError(
+ nodeTypeName + ": cannot create lightDataArrayOut attr: "
+ + st.errorString()
+ );
+ return st;
+ }
+ cAttr.addChild(aLightDirectionOut);
+ cAttr.addChild(aLightIntensityOut);
+ cAttr.addChild(aLightAmbientOut);
+ cAttr.addChild(aLightDiffuseOut);
+ cAttr.addChild(aLightSpecularOut);
+ cAttr.addChild(aLightShadowFractionOut);
+ cAttr.addChild(aPreShadowIntensityOut);
+ cAttr.addChild(aLightBlindDataOut);
+ cAttr.setArray(true);
+ cAttr.setUsesArrayDataBuilder(true);
+ cAttr.setHidden(true);
+ cAttr.setStorable(false);
+ st = addAttribute(aLightDataArrayOut);
+ if (!st)
+ {
+ MGlobal::displayError(
+ nodeTypeName + ": cannot add lightDataArrayOut attr: "
+ + st.errorString()
+ );
+ return st;
+ }
+
+
+ //
+ // Set up attribute dependencies.
+ //
+ attributeAffects(aLightDataArray, aLightDataArrayOut);
+ attributeAffects(aMatrixEyeToWorld, aLightDataArrayOut);
+ attributeAffects(aNormalCamera, aLightDataArrayOut);
+ attributeAffects(aObjectId, aLightDataArrayOut);
+ attributeAffects(aPointWorld, aLightDataArrayOut);
+ attributeAffects(aRayDepth, aLightDataArrayOut);
+ attributeAffects(aRayDirection, aLightDataArrayOut);
+ attributeAffects(aRayOrigin, aLightDataArrayOut);
+
+ return MS::kSuccess;
+}
+
+
+void shaveShadowFilter::postConstructor( )
+{
+// %%% Can we safely do this, given the use of globals by the Shave
+// engine?
+//
+// setMPSafe(true);
+}
+
+
+MStatus shaveShadowFilter::compute(const MPlug& plug, MDataBlock& datablock)
+{
+ if ((plug == aLightDataArrayOut)
+ || (plug.parent() == aLightDataArrayOut))
+ {
+ const MFloatVector& point = datablock
+ .inputValue(aPointWorld)
+ .asFloatVector();
+
+ const MFloatVector& normal = datablock
+ .inputValue(aNormalCamera)
+ .asFloatVector();
+
+ MArrayDataHandle lightArrayIn =
+ datablock.inputArrayValue(aLightDataArray);
+
+ unsigned int numAffectingLights = 0;
+ unsigned int numLights = lightArrayIn.elementCount();
+
+ MArrayDataBuilder lightArrayOutBuilder(
+ &datablock, aLightDataArrayOut, numLights
+ );
+
+ int blindData;
+ unsigned int i;
+ MFloatVector intensity;
+ MFloatVector lightDir;
+ float lightShadow = 0.0f;
+ float netIllum = 0.0f;
+ float netShadow = 0.0f;
+ float preShadowIntensity;
+ float shadowFraction;
+ float totalPreShadowIntensity = 0.0f;
+
+ VERT wpoint;
+ wpoint.x = point.x;
+ wpoint.y = point.y;
+ wpoint.z = point.z;
+
+ for (i = 0; i < numLights; i++)
+ {
+ MDataHandle lightIn = lightArrayIn.inputValue();
+ MDataHandle lightOut = lightArrayOutBuilder.addElement(
+ lightArrayIn.elementIndex()
+ );
+
+ //
+ // Get the values for this light.
+ //
+ blindData = lightIn.child(aLightBlindData).asAddr();
+ intensity = lightIn.child(aLightIntensity).asFloatVector();
+ lightDir = lightIn.child(aLightDirection).asFloatVector();
+ preShadowIntensity = lightIn.child(aPreShadowIntensity).asFloat();
+ shadowFraction = lightIn.child(aLightShadowFraction).asFloat();
+
+ //
+ // Checking for hair shadows is expensive, so let's avoid it if
+ // at all possible.
+ //
+ if ((preShadowIntensity > 0.0f)
+ && (shadowFraction < 1.0f)
+ && (shaveShadowDensityGlob > 0.0f)
+ && (intensity.x + intensity.y + intensity.z > 0.0f))
+ {
+ //
+ // If the surface normal is facing away from the light then
+ // there won't be any hair shadows on it.
+ //
+ float hairIllum = 1.0f;
+
+ if (lightDir * normal > 0.04f)
+ {
+ //
+ // 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;
+
+ 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();
+
+ lightDir *= camToWorld;
+ lightIndex = shaveUtil::getLightIndex(point, lightDir);
+ }
+
+ 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);
+
+ //
+ // Apply the hair's dimming effect to the light's
+ // intensity.
+ //
+ intensity *= hairIllum;
+
+ //
+ // Add the dimming effect to the light's shadow
+ // fraction.
+ //
+ shadowFraction += 1.0f - hairIllum;
+
+ if (shadowFraction > 1.0f) shadowFraction = 1.0f;
+ }
+ }
+ }
+
+ // Fill in the output values.
+ lightOut.child(aLightDirectionOut).set(lightDir);
+ lightOut.child(aLightIntensityOut).set(intensity);
+ lightOut.child(aLightShadowFractionOut).set(shadowFraction);
+ lightOut.child(aLightBlindDataOut).set(blindData);
+ lightOut.child(aPreShadowIntensityOut).set(preShadowIntensity);
+
+ lightOut.child(aLightAmbientOut).set(
+ lightIn.child(aLightAmbient).asBool()
+ );
+
+ lightOut.child(aLightDiffuseOut).set(
+ lightIn.child(aLightDiffuse).asBool()
+ );
+
+ lightOut.child(aLightSpecularOut).set(
+ lightIn.child(aLightSpecular).asBool()
+ );
+
+ if (!lightArrayIn.next()) break;
+ }
+
+ datablock.outputArrayValue(aLightDataArrayOut).set(
+ lightArrayOutBuilder
+ );
+ }
+ else
+ return MS::kUnknownParameter;
+
+ return MS::kSuccess;
+}
+
+