void CScriptedShapeTranslator::RunScripts(AtNode *atNode, unsigned int step, bool update) { std::map<std::string, CScriptedTranslator>::iterator translatorIt; MFnDependencyNode fnNode(GetMayaObject()); translatorIt = gTranslators.find(fnNode.typeName().asChar()); if (translatorIt == gTranslators.end()) { AiMsgError("[mtoa.scriptedTranslators] No command to export node \"%s\" of type %s.", fnNode.name().asChar(), fnNode.typeName().asChar()); return; } MString exportCmd = translatorIt->second.exportCmd; MString cleanupCmd = translatorIt->second.cleanupCmd; MFnDagNode node(m_dagPath.node()); bool isMasterDag = false; bool transformBlur = IsMotionBlurEnabled(MTOA_MBLUR_OBJECT) && IsLocalMotionBlurEnabled(); bool deformBlur = IsMotionBlurEnabled(MTOA_MBLUR_DEFORM) && IsLocalMotionBlurEnabled(); char buffer[64]; MString command = exportCmd; command += "("; sprintf(buffer, "%f", GetExportFrame()); command += buffer; command += ", "; sprintf(buffer, "%d", step); command += buffer; command += ", "; // current sample frame sprintf(buffer, "%f", GetSampleFrame(m_session, step)); command += buffer; command += ", "; // List of arnold attributes the custom shape export command has overriden MStringArray attrs; if (!m_masterNode) { command += "(\"" + m_dagPath.partialPathName() + "\", \""; command += AiNodeGetName(atNode); command += "\"), None)"; isMasterDag = true; } else { command += "(\"" + m_dagPath.partialPathName() + "\", \""; command += AiNodeGetName(atNode); command += "\"), (\"" + GetMasterInstance().partialPathName() + "\", \""; command += AiNodeGetName(m_masterNode); command += "\"))"; } MStatus status = MGlobal::executePythonCommand(command, attrs); if (!status) { AiMsgError("[mtoa.scriptedTranslators] Failed to export node \"%s\".", node.name().asChar()); return; } // Build set of attributes already processed std::set<std::string> attrsSet; for (unsigned int i=0; i<attrs.length(); ++i) { attrsSet.insert(attrs[i].asChar()); } std::set<std::string>::iterator attrsEnd = attrsSet.end(); // Should be getting displacement shader from master instance only // as arnold do not support displacement shader overrides for ginstance MFnDependencyNode masterShadingEngine; MFnDependencyNode shadingEngine; float dispPadding = -AI_BIG; float dispHeight = 1.0f; float dispZeroValue = 0.0f; bool dispAutobump = false; bool outputDispPadding = false; bool outputDispHeight = false; bool outputDispZeroValue = false; bool outputDispAutobump = false; const AtNodeEntry *anodeEntry = AiNodeGetNodeEntry(atNode); GetShapeInstanceShader(m_dagPath, shadingEngine); if (!IsMasterInstance()) { GetShapeInstanceShader(GetMasterInstance(), masterShadingEngine); } else { masterShadingEngine.setObject(shadingEngine.object()); } AtMatrix matrix; MMatrix mmatrix = m_dagPath.inclusiveMatrix(); ConvertMatrix(matrix, mmatrix); // Set transformation matrix if (attrsSet.find("matrix") == attrsEnd) { if (HasParameter(anodeEntry, "matrix")) { if (transformBlur) { if (step == 0) { AtArray* matrices = AiArrayAllocate(1, GetNumMotionSteps(), AI_TYPE_MATRIX); AiArraySetMtx(matrices, step, matrix); AiNodeSetArray(atNode, "matrix", matrices); } else { AtArray* matrices = AiNodeGetArray(atNode, "matrix"); AiArraySetMtx(matrices, step, matrix); } } else { AiNodeSetMatrix(atNode, "matrix", matrix); } } } // Set bounding box if (attrsSet.find("min") == attrsEnd && attrsSet.find("max") == attrsEnd) { // Now check if min and max parameters are valid parameter names on arnold node if (HasParameter(anodeEntry, "min") != 0 && HasParameter(anodeEntry, "max") != 0) { if (step == 0) { MBoundingBox bbox = node.boundingBox(); MPoint bmin = bbox.min(); MPoint bmax = bbox.max(); AiNodeSetPnt(atNode, "min", static_cast<float>(bmin.x), static_cast<float>(bmin.y), static_cast<float>(bmin.z)); AiNodeSetPnt(atNode, "max", static_cast<float>(bmax.x), static_cast<float>(bmax.y), static_cast<float>(bmax.z)); } else { if (transformBlur || deformBlur) { AtPoint cmin = AiNodeGetPnt(atNode, "min"); AtPoint cmax = AiNodeGetPnt(atNode, "max"); MBoundingBox bbox = node.boundingBox(); MPoint bmin = bbox.min(); MPoint bmax = bbox.max(); if (bmin.x < cmin.x) cmin.x = static_cast<float>(bmin.x); if (bmin.y < cmin.y) cmin.y = static_cast<float>(bmin.y); if (bmin.z < cmin.z) cmin.z = static_cast<float>(bmin.z); if (bmax.x > cmax.x) cmax.x = static_cast<float>(bmax.x); if (bmax.y > cmax.y) cmax.y = static_cast<float>(bmax.y); if (bmax.z > cmax.z) cmax.z = static_cast<float>(bmax.z); AiNodeSetPnt(atNode, "min", cmin.x, cmin.y, cmin.z); AiNodeSetPnt(atNode, "max", cmax.x, cmax.y, cmax.z); } } } } if (step == 0) { // Set common attributes MPlug plug; if (AiNodeIs(atNode, "procedural")) { // Note: it is up to the procedural to properly forward (or not) those parameters to the node // it creates if (attrsSet.find("subdiv_type") == attrsEnd) { plug = FindMayaPlug("subdiv_type"); if (plug.isNull()) { plug = FindMayaPlug("aiSubdivType"); } if (!plug.isNull() && HasParameter(anodeEntry, "subdiv_type", atNode, "constant INT")) { AiNodeSetInt(atNode, "subdiv_type", plug.asInt()); } } if (attrsSet.find("subdiv_iterations") == attrsEnd) { plug = FindMayaPlug("subdiv_iterations"); if (plug.isNull()) { plug = FindMayaPlug("aiSubdivIterations"); } if (!plug.isNull() && HasParameter(anodeEntry, "subdiv_iterations", atNode, "constant BYTE")) { AiNodeSetByte(atNode, "subdiv_iterations", plug.asInt()); } } if (attrsSet.find("subdiv_adaptive_metric") == attrsEnd) { plug = FindMayaPlug("subdiv_adaptive_metric"); if (plug.isNull()) { plug = FindMayaPlug("aiSubdivAdaptiveMetric"); } if (!plug.isNull() && HasParameter(anodeEntry, "subdiv_adaptive_metric", atNode, "constant INT")) { AiNodeSetInt(atNode, "subdiv_adaptive_metric", plug.asInt()); } } if (attrsSet.find("subdiv_pixel_error") == attrsEnd) { plug = FindMayaPlug("subdiv_pixel_error"); if (plug.isNull()) { plug = FindMayaPlug("aiSubdivPixelError"); } if (!plug.isNull() && HasParameter(anodeEntry, "subdiv_pixel_error", atNode, "constant FLOAT")) { AiNodeSetFlt(atNode, "subdiv_pixel_error", plug.asFloat()); } } if (attrsSet.find("subdiv_dicing_camera") == attrsEnd) { plug = FindMayaPlug("subdiv_dicing_camera"); if (plug.isNull()) { plug = FindMayaPlug("aiSubdivDicingCamera"); } if (!plug.isNull() && HasParameter(anodeEntry, "subdiv_dicing_camera", atNode, "constant NODE")) { AtNode *cameraNode = NULL; MPlugArray plugs; plug.connectedTo(plugs, true, false); if (plugs.length() == 1) { MFnDagNode camDag(plugs[0].node()); MDagPath camPath; if (camDag.getPath(camPath) == MS::kSuccess) { cameraNode = ExportDagPath(camPath); } } AiNodeSetPtr(atNode, "subdiv_dicing_camera", cameraNode); } } if (attrsSet.find("subdiv_uv_smoothing") == attrsEnd) { plug = FindMayaPlug("subdiv_uv_smoothing"); if (plug.isNull()) { plug = FindMayaPlug("aiSubdivUvSmoothing"); } if (!plug.isNull() && HasParameter(anodeEntry, "subdiv_uv_smoothing", atNode, "constant INT")) { AiNodeSetInt(atNode, "subdiv_uv_smoothing", plug.asInt()); } } if (attrsSet.find("subdiv_smooth_derivs") == attrsEnd) { plug = FindMayaPlug("aiSubdivSmoothDerivs"); if (!plug.isNull() && HasParameter(anodeEntry, "subdiv_smooth_derivs", atNode, "constant BOOL")) { AiNodeSetBool(atNode, "subdiv_smooth_derivs", plug.asBool()); } } if (attrsSet.find("smoothing") == attrsEnd) { // Use maya shape built-in attribute plug = FindMayaPlug("smoothShading"); if (!plug.isNull() && HasParameter(anodeEntry, "smoothing", atNode, "constant BOOL")) { AiNodeSetBool(atNode, "smoothing", plug.asBool()); } } if (attrsSet.find("disp_height") == attrsEnd) { plug = FindMayaPlug("aiDispHeight"); if (!plug.isNull()) { outputDispHeight = true; dispHeight = plug.asFloat(); } } if (attrsSet.find("disp_zero_value") == attrsEnd) { plug = FindMayaPlug("aiDispZeroValue"); if (!plug.isNull()) { outputDispZeroValue = true; dispZeroValue = plug.asFloat(); } } if (attrsSet.find("disp_autobump") == attrsEnd) { plug = FindMayaPlug("aiDispAutobump"); if (!plug.isNull()) { outputDispAutobump = true; dispAutobump = plug.asBool(); } } if (attrsSet.find("disp_padding") == attrsEnd) { plug = FindMayaPlug("aiDispPadding"); if (!plug.isNull()) { outputDispPadding = true; dispPadding = MAX(dispPadding, plug.asFloat()); } } // Set diplacement shader if (attrsSet.find("disp_map") == attrsEnd) { if (masterShadingEngine.object() != MObject::kNullObj) { MPlugArray shaderConns; MPlug shaderPlug = masterShadingEngine.findPlug("displacementShader"); shaderPlug.connectedTo(shaderConns, true, false); if (shaderConns.length() > 0) { MFnDependencyNode dispNode(shaderConns[0].node()); plug = dispNode.findPlug("aiDisplacementPadding"); if (!plug.isNull()) { outputDispPadding = true; dispPadding = MAX(dispPadding, plug.asFloat()); } plug = dispNode.findPlug("aiDisplacementAutoBump"); if (!plug.isNull()) { outputDispAutobump = true; dispAutobump = dispAutobump || plug.asBool(); } if (HasParameter(anodeEntry, "disp_map", atNode, "constant ARRAY NODE")) { AtNode *dispImage = ExportNode(shaderConns[0]); AiNodeSetArray(atNode, "disp_map", AiArrayConvert(1, 1, AI_TYPE_NODE, &dispImage)); } } } } if (outputDispHeight && HasParameter(anodeEntry, "disp_height", atNode, "constant FLOAT")) { AiNodeSetFlt(atNode, "disp_height", dispHeight); } if (outputDispZeroValue && HasParameter(anodeEntry, "disp_zero_value", atNode, "constant FLOAT")) { AiNodeSetFlt(atNode, "disp_zero_value", dispZeroValue); } if (outputDispPadding && HasParameter(anodeEntry, "disp_padding", atNode, "constant FLOAT")) { AiNodeSetFlt(atNode, "disp_padding", dispPadding); } if (outputDispAutobump && HasParameter(anodeEntry, "disp_autobump", atNode, "constant BOOL")) { AiNodeSetBool(atNode, "disp_autobump", dispAutobump); } // Old point based SSS parameter if (attrsSet.find("sss_sample_distribution") == attrsEnd) { plug = FindMayaPlug("sss_sample_distribution"); if (plug.isNull()) { plug = FindMayaPlug("aiSssSampleDistribution"); } if (!plug.isNull() && HasParameter(anodeEntry, "sss_sample_distribution", atNode, "constant INT")) { AiNodeSetInt(atNode, "sss_sample_distribution", plug.asInt()); } } // Old point based SSS parameter if (attrsSet.find("sss_sample_spacing") == attrsEnd) { plug = FindMayaPlug("sss_sample_spacing"); if (plug.isNull()) { plug = FindMayaPlug("aiSssSampleSpacing"); } if (!plug.isNull() && HasParameter(anodeEntry, "sss_sample_spacing", atNode, "constant FLOAT")) { AiNodeSetFlt(atNode, "sss_sample_spacing", plug.asFloat()); } } if (attrsSet.find("min_pixel_width") == attrsEnd) { plug = FindMayaPlug("aiMinPixelWidth"); if (!plug.isNull() && HasParameter(anodeEntry, "min_pixel_width", atNode, "constant FLOAT")) { AiNodeSetFlt(atNode, "min_pixel_width", plug.asFloat()); } } if (attrsSet.find("mode") == attrsEnd) { plug = FindMayaPlug("aiMode"); if (!plug.isNull() && HasParameter(anodeEntry, "mode", atNode, "constant INT")) { AiNodeSetInt(atNode, "mode", plug.asShort()); } } if (attrsSet.find("basis") == attrsEnd) { plug = FindMayaPlug("aiBasis"); if (!plug.isNull() && HasParameter(anodeEntry, "basis", atNode, "constant INT")) { AiNodeSetInt(atNode, "basis", plug.asShort()); } } } if (AiNodeIs(atNode, "ginstance")) { if (attrsSet.find("node") == attrsEnd) { AiNodeSetPtr(atNode, "node", m_masterNode); } if (attrsSet.find("inherit_xform") == attrsEnd) { AiNodeSetBool(atNode, "inherit_xform", false); } } else { // box or procedural if (attrsSet.find("step_size") == attrsEnd) { plug = FindMayaPlug("step_size"); if (plug.isNull()) { plug = FindMayaPlug("aiStepSize"); } if (!plug.isNull() && HasParameter(anodeEntry, "step_size", atNode, "constant FLOAT")) { AiNodeSetFlt(atNode, "step_size", plug.asFloat()); } } } if (attrsSet.find("sidedness") == attrsEnd) { // Use maya shape built-in attribute plug = FindMayaPlug("doubleSided"); if (!plug.isNull() && HasParameter(anodeEntry, "sidedness", atNode, "constant BYTE")) { AiNodeSetByte(atNode, "sidedness", plug.asBool() ? AI_RAY_ALL : 0); // Only set invert_normals if doubleSided attribute could be found if (!plug.asBool() && attrsSet.find("invert_normals") == attrsEnd) { // Use maya shape built-in attribute plug = FindMayaPlug("opposite"); if (!plug.isNull() && HasParameter(anodeEntry, "invert_normals", atNode, "constant BOOL")) { AiNodeSetBool(atNode, "invert_normals", plug.asBool()); } } } } if (attrsSet.find("receive_shadows") == attrsEnd) { // Use maya shape built-in attribute plug = FindMayaPlug("receiveShadows"); if (!plug.isNull() && HasParameter(anodeEntry, "receive_shadows", atNode, "constant BOOL")) { AiNodeSetBool(atNode, "receive_shadows", plug.asBool()); } } if (attrsSet.find("self_shadows") == attrsEnd) { plug = FindMayaPlug("self_shadows"); if (plug.isNull()) { plug = FindMayaPlug("aiSelfShadows"); } if (!plug.isNull() && HasParameter(anodeEntry, "self_shadows", atNode, "constant BOOL")) { AiNodeSetBool(atNode, "self_shadows", plug.asBool()); } } if (attrsSet.find("opaque") == attrsEnd) { plug = FindMayaPlug("opaque"); if (plug.isNull()) { plug = FindMayaPlug("aiOpaque"); } if (!plug.isNull() && HasParameter(anodeEntry, "opaque", atNode, "constant BOOL")) { AiNodeSetBool(atNode, "opaque", plug.asBool()); } } if (attrsSet.find("visibility") == attrsEnd) { if (HasParameter(anodeEntry, "visibility", atNode, "constant BYTE")) { int visibility = AI_RAY_ALL; // Use maya shape built-in attribute plug = FindMayaPlug("castsShadows"); if (!plug.isNull() && !plug.asBool()) { visibility &= ~AI_RAY_SHADOW; } // Use maya shape built-in attribute plug = FindMayaPlug("primaryVisibility"); if (!plug.isNull() && !plug.asBool()) { visibility &= ~AI_RAY_CAMERA; } // Use maya shape built-in attribute plug = FindMayaPlug("visibleInReflections"); if (!plug.isNull() && !plug.asBool()) { visibility &= ~AI_RAY_REFLECTED; } // Use maya shape built-in attribute plug = FindMayaPlug("visibleInRefractions"); if (!plug.isNull() && !plug.asBool()) { visibility &= ~AI_RAY_REFRACTED; } plug = FindMayaPlug("diffuse_visibility"); if (plug.isNull()) { plug = FindMayaPlug("aiVisibleInDiffuse"); } if (!plug.isNull() && !plug.asBool()) { visibility &= ~AI_RAY_DIFFUSE; } plug = FindMayaPlug("glossy_visibility"); if (plug.isNull()) { plug = FindMayaPlug("aiVisibleInGlossy"); } if (!plug.isNull() && !plug.asBool()) { visibility &= ~AI_RAY_GLOSSY; } AiNodeSetByte(atNode, "visibility", visibility & 0xFF); } } if (attrsSet.find("sss_setname") == attrsEnd) { plug = FindMayaPlug("aiSssSetname"); if (!plug.isNull() && plug.asString().length() > 0) { if (HasParameter(anodeEntry, "sss_setname", atNode, "constant STRING")) { AiNodeSetStr(atNode, "sss_setname", plug.asString().asChar()); } } } // Set surface shader if (HasParameter(anodeEntry, "shader", atNode, "constant NODE")) { if (attrsSet.find("shader") == attrsEnd) { if (shadingEngine.object() != MObject::kNullObj) { AtNode *shader = ExportNode(shadingEngine.findPlug("message")); if (shader != NULL) { const AtNodeEntry *entry = AiNodeGetNodeEntry(shader); if (AiNodeEntryGetType(entry) != AI_NODE_SHADER) { MGlobal::displayWarning("[mtoaScriptedTranslators] Node generated from \"" + shadingEngine.name() + "\" of type " + shadingEngine.typeName() + " for shader is not a shader but a " + MString(AiNodeEntryGetTypeName(entry))); } else { AiNodeSetPtr(atNode, "shader", shader); if (AiNodeLookUpUserParameter(atNode, "mtoa_shading_groups") == 0) { AiNodeDeclare(atNode, "mtoa_shading_groups", "constant ARRAY NODE"); AiNodeSetArray(atNode, "mtoa_shading_groups", AiArrayConvert(1, 1, AI_TYPE_NODE, &shader)); } } } } } } } ExportLightLinking(atNode); MPlug plug = FindMayaPlug("aiTraceSets"); if (!plug.isNull()) { ExportTraceSets(atNode, plug); } // Call cleanup command on last export step if (!IsMotionBlurEnabled() || !IsLocalMotionBlurEnabled() || int(step) >= (int(GetNumMotionSteps()) - 1)) { if (HasParameter(anodeEntry, "disp_padding", atNode)) { float padding = AiNodeGetFlt(atNode, "disp_padding"); AtPoint cmin = AiNodeGetPnt(atNode, "min"); AtPoint cmax = AiNodeGetPnt(atNode, "max"); cmin.x -= padding; cmin.y -= padding; cmin.z -= padding; cmax.x += padding; cmax.y += padding; cmax.z += padding; AiNodeSetPnt(atNode, "min", cmin.x, cmin.y, cmin.z); AiNodeSetPnt(atNode, "max", cmax.x, cmax.y, cmax.z); } if (cleanupCmd != "") { command = cleanupCmd += "((\"" + m_dagPath.partialPathName() + "\", \""; command += AiNodeGetName(atNode); command += "\"), "; if (!m_masterNode) { command += "None)"; } else { command += "(\"" + GetMasterInstance().partialPathName() + "\", \""; command += AiNodeGetName(m_masterNode); command += "\"))"; } status = MGlobal::executePythonCommand(command); if (!status) { AiMsgError("[mtoa.scriptedTranslators] Failed to cleanup node \"%s\".", node.name().asChar()); } } } }
virtual void ExportProcedural( AtNode *node ) { // do basic node export ExportMatrix( node, 0 ); AtNode *shader = arnoldShader(); if( shader ) { AiNodeSetPtr( node, "shader", shader ); } AiNodeSetInt( node, "visibility", ComputeVisibility() ); MPlug plug = FindMayaObjectPlug( "receiveShadows" ); if( !plug.isNull() ) { AiNodeSetBool( node, "receive_shadows", plug.asBool() ); } plug = FindMayaObjectPlug( "aiSelfShadows" ); if( !plug.isNull() ) { AiNodeSetBool( node, "self_shadows", plug.asBool() ); } plug = FindMayaObjectPlug( "aiOpaque" ); if( !plug.isNull() ) { AiNodeSetBool( node, "opaque", plug.asBool() ); } // export any shading groups or displacement shaders which look like they // may be connected to procedural parameters. this ensures that maya shaders // the procedural will expect to find at rendertime will be exported to the // ass file (they otherwise might not be if they're not assigned to any objects). exportShadingInputs(); // now set the procedural-specific parameters MFnDagNode fnDagNode( m_dagPath ); MBoundingBox bound = fnDagNode.boundingBox(); AiNodeSetPnt( node, "min", bound.min().x, bound.min().y, bound.min().z ); AiNodeSetPnt( node, "max", bound.max().x, bound.max().y, bound.max().z ); const char *dsoPath = getenv( "IECOREARNOLD_PROCEDURAL_PATH" ); AiNodeSetStr( node, "dso", dsoPath ? dsoPath : "ieProcedural.so" ); AiNodeDeclare( node, "className", "constant STRING" ); AiNodeDeclare( node, "classVersion", "constant INT" ); AiNodeDeclare( node, "parameterValues", "constant ARRAY STRING" ); // cast should be ok as we're registered to only work on procedural holders IECoreMaya::ProceduralHolder *pHolder = static_cast<IECoreMaya::ProceduralHolder *>( fnDagNode.userNode() ); std::string className; int classVersion; IECore::ParameterisedProceduralPtr procedural = pHolder->getProcedural( &className, &classVersion ); AiNodeSetStr( node, "className", className.c_str() ); AiNodeSetInt( node, "classVersion", classVersion ); IECorePython::ScopedGILLock gilLock; try { boost::python::object parser = IECoreMaya::PythonCmd::globalContext()["IECore"].attr( "ParameterParser" )(); boost::python::object serialised = parser.attr( "serialise" )( procedural->parameters() ); size_t numStrings = IECorePython::len( serialised ); AtArray *stringArray = AiArrayAllocate( numStrings, 1, AI_TYPE_STRING ); for( size_t i=0; i<numStrings; i++ ) { std::string s = boost::python::extract<std::string>( serialised[i] ); // hack to workaround ass parsing errors /// \todo Remove when we get the Arnold version that fixes this for( size_t c = 0; c<s.size(); c++ ) { if( s[c] == '#' ) { s[c] = '@'; } } AiArraySetStr( stringArray, i, s.c_str() ); } AiNodeSetArray( node, "parameterValues", stringArray ); } catch( boost::python::error_already_set ) { PyErr_Print(); } }
/* static */ bool px_vp20Utils::RenderBoundingBox( const MBoundingBox& bounds, const GfVec4f& color, const MMatrix& worldViewMat, const MMatrix& projectionMat) { static const GfVec3f cubeLineVertices[24] = { // Vertical edges GfVec3f(-0.5f, -0.5f, 0.5f), GfVec3f(-0.5f, 0.5f, 0.5f), GfVec3f(0.5f, -0.5f, 0.5f), GfVec3f(0.5f, 0.5f, 0.5f), GfVec3f(0.5f, -0.5f, -0.5f), GfVec3f(0.5f, 0.5f, -0.5f), GfVec3f(-0.5f, -0.5f, -0.5f), GfVec3f(-0.5f, 0.5f, -0.5f), // Top face edges GfVec3f(-0.5f, 0.5f, 0.5f), GfVec3f(0.5f, 0.5f, 0.5f), GfVec3f(0.5f, 0.5f, 0.5f), GfVec3f(0.5f, 0.5f, -0.5f), GfVec3f(0.5f, 0.5f, -0.5f), GfVec3f(-0.5f, 0.5f, -0.5f), GfVec3f(-0.5f, 0.5f, -0.5f), GfVec3f(-0.5f, 0.5f, 0.5f), // Bottom face edges GfVec3f(-0.5f, -0.5f, 0.5f), GfVec3f(0.5f, -0.5f, 0.5f), GfVec3f(0.5f, -0.5f, 0.5f), GfVec3f(0.5f, -0.5f, -0.5f), GfVec3f(0.5f, -0.5f, -0.5f), GfVec3f(-0.5f, -0.5f, -0.5f), GfVec3f(-0.5f, -0.5f, -0.5f), GfVec3f(-0.5f, -0.5f, 0.5f), }; static const std::string vertexShaderSource( "#version 140\n" "\n" "in vec3 position;\n" "uniform mat4 mvpMatrix;\n" "\n" "void main()\n" "{\n" " gl_Position = vec4(position, 1.0) * mvpMatrix;\n" "}\n"); static const std::string fragmentShaderSource( "#version 140\n" "\n" "uniform vec4 color;\n" "out vec4 outColor;\n" "\n" "void main()\n" "{\n" " outColor = color;\n" "}\n"); PxrMayaGLSLProgram renderBoundsProgram; if (!renderBoundsProgram.CompileShader(GL_VERTEX_SHADER, vertexShaderSource)) { MGlobal::displayError("Failed to compile bounding box vertex shader"); return false; } if (!renderBoundsProgram.CompileShader(GL_FRAGMENT_SHADER, fragmentShaderSource)) { MGlobal::displayError("Failed to compile bounding box fragment shader"); return false; } if (!renderBoundsProgram.Link()) { MGlobal::displayError("Failed to link bounding box render program"); return false; } if (!renderBoundsProgram.Validate()) { MGlobal::displayError("Failed to validate bounding box render program"); return false; } GLuint renderBoundsProgramId = renderBoundsProgram.GetProgramId(); glUseProgram(renderBoundsProgramId); // Populate an array buffer with the cube line vertices. GLuint cubeLinesVBO; glGenBuffers(1, &cubeLinesVBO); glBindBuffer(GL_ARRAY_BUFFER, cubeLinesVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(cubeLineVertices), cubeLineVertices, GL_STATIC_DRAW); // Create a transformation matrix from the bounding box's center and // dimensions. MTransformationMatrix bboxTransformMatrix = MTransformationMatrix::identity; bboxTransformMatrix.setTranslation(bounds.center(), MSpace::kTransform); const double scales[3] = { bounds.width(), bounds.height(), bounds.depth() }; bboxTransformMatrix.setScale(scales, MSpace::kTransform); const MMatrix mvpMatrix = bboxTransformMatrix.asMatrix() * worldViewMat * projectionMat; GLfloat mvpMatrixArray[4][4]; mvpMatrix.get(mvpMatrixArray); // Populate the shader variables. GLuint mvpMatrixLocation = glGetUniformLocation(renderBoundsProgramId, "mvpMatrix"); glUniformMatrix4fv(mvpMatrixLocation, 1, GL_TRUE, &mvpMatrixArray[0][0]); GLuint colorLocation = glGetUniformLocation(renderBoundsProgramId, "color"); glUniform4fv(colorLocation, 1, color.data()); // Enable the position attribute and draw. glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); glDrawArrays(GL_LINES, 0, sizeof(cubeLineVertices)); glDisableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); glDeleteBuffers(1, &cubeLinesVBO); glUseProgram(0); return true; }
void simpleFluidEmitter::volumeFluidEmitter( MFnFluid& fluid, const MMatrix& fluidWorldMatrix, int plugIndex, MDataBlock& block, double dt, double conversion, double dropoff ) //============================================================================== // // Method: // // simpleFluidEmitter::volumeFluidEmitter // // Description: // // Emits fluid from points distributed over the surface of the // emitter's owner object. // // Parameters: // // fluid: fluid into which we are emitting // fluidWorldMatrix: object->world matrix for the fluid // plugIndex: identifies which fluid connected to the emitter // we are emitting into // block: datablock for the emitter, to retrieve attribute // values // dt: time delta for this frame // conversion: mapping from UI emission rates to internal units // dropoff: specifies how much emission rate drops off as // we move away from the local y-axis of the // volume emitter shape. // //============================================================================== { // get emitter position and relevant matrices // MPoint emitterPos = getWorldPosition(); MMatrix emitterWorldMatrix = getWorldMatrix(); MMatrix fluidInverseWorldMatrix = fluidWorldMatrix.inverse(); // get emission rates for density, fuel, heat, and emission color // double densityEmit = fluidDensityEmission( block ); double fuelEmit = fluidFuelEmission( block ); double heatEmit = fluidHeatEmission( block ); bool doEmitColor = fluidEmitColor( block ); MColor emitColor = fluidColor( block ); // rate modulation based on frame time, user value conversion factor, and // standard emitter "rate" value (not actually exposed in most fluid // emitters, but there anyway). // double theRate = getRate(block) * dt * conversion; // find the voxels that intersect the bounding box of the volume // primitive associated with the emitter // MBoundingBox bbox; if( !volumePrimitiveBoundingBox( bbox ) ) { // shouldn't happen // return; } // transform volume primitive into fluid space // bbox.transformUsing( emitterWorldMatrix ); bbox.transformUsing( fluidInverseWorldMatrix ); MPoint lowCorner = bbox.min(); MPoint highCorner = bbox.max(); // see if autoresize to emitter is on, so we can resize before emitting // // unfortunately, we need the fluidShape itself in order to check // we'll just look at the first connected fluid, // walking the multi is left as an excercise for the reader // similarly, determining whether there is start frame emission // and resizing at the start frame, or not, is left as an excercise // and finally, emission with autoResize will need to include the dynamicOffset // MObject thisObj = thisMObject(); MFnDependencyNode nodeFn(thisObj); bool autoResize = false; bool resizeToEmitter = false; MPlug fnPlug = nodeFn.findPlug("emissionFunction"); if(fnPlug.isConnected()) { MPlugArray connections; fnPlug.connectedTo(connections, false, true); if (connections.length() > 0) { MObject sourceNode = connections[0].node(); if (sourceNode.hasFn(MFn::kFluid)) { MFnFluid fluidFn(sourceNode); autoResize = fluidFn.isAutoResize(); resizeToEmitter = fluidFn.isResizeToEmitter(); if(autoResize && resizeToEmitter) { fluidFn.expandToInclude(lowCorner, highCorner); } } } } if(autoResize && resizeToEmitter) { fluid.updateGrid (); } // get voxel dimensions and sizes (object space) // double size[3]; unsigned int res[3]; fluid.getDimensions( size[0], size[1], size[2] ); fluid.getResolution( res[0], res[1], res[2] ); // voxel sizes double dx = size[0] / res[0]; double dy = size[1] / res[1]; double dz = size[2] / res[2]; // voxel centers double Ox = -size[0]/2; double Oy = -size[1]/2; double Oz = -size[2]/2; // get fluid voxel coord range of bounding box // int3 lowCoords; int3 highCoords; fluid.toGridIndex( lowCorner, lowCoords ); fluid.toGridIndex( highCorner, highCoords ); int i; for ( i = 0; i < 3; i++ ) { if ( lowCoords[i] < 0 ) { lowCoords[i] = 0; } else if ( lowCoords[i] > ((int)res[i])-1 ) { lowCoords[i] = ((int)res[i])-1; } if ( highCoords[i] < 0 ) { highCoords[i] = 0; } else if ( highCoords[i] > ((int)res[i])-1 ) { highCoords[i] = ((int)res[i])-1; } } // figure out the emitter size relative to the voxel size, and compute // a per-voxel sampling rate that uses 1 sample/voxel for emitters that // are >= 2 voxels big in all dimensions. For smaller emitters, use up // to 8 samples per voxel. // double emitterVoxelSize[3]; emitterVoxelSize[0] = (highCorner[0]-lowCorner[0])/dx; emitterVoxelSize[1] = (highCorner[1]-lowCorner[1])/dy; emitterVoxelSize[2] = (highCorner[2]-lowCorner[2])/dz; double minVoxelSize = MIN(emitterVoxelSize[0],MIN(emitterVoxelSize[1],emitterVoxelSize[2])); if( minVoxelSize < 1.0 ) { minVoxelSize = 1.0; } int maxSamples = 8; int numSamples = (int)(8.0/(minVoxelSize*minVoxelSize*minVoxelSize) + 0.5); if( numSamples < 1 ) numSamples = 1; if( numSamples > maxSamples ) numSamples = maxSamples; // non-jittered, just use one sample in the voxel center. Should replace // with uniform sampling pattern. // bool jitter = fluidJitter(block); if( !jitter ) { numSamples = 1; } // for each voxel that could potentially intersect the volume emitter // primitive, take some samples in the voxel. For those inside the // volume, compute their dropoff relative to the primitive's local y-axis, // and emit an appropriate amount into the voxel. // for( i = lowCoords[0]; i <= highCoords[0]; i++ ) { double x = Ox + (i+0.5)*dx; for( int j = lowCoords[1]; j < highCoords[1]; j++ ) { double y = Oy + (j+0.5)*dy; for( int k = lowCoords[2]; k < highCoords[2]; k++ ) { double z = Oz + (k+0.5)*dz; for ( int si = 0; si < numSamples; si++) { // compute voxel sample point (object space) // double rx, ry, rz; if(jitter) { rx = x + dx*(randgen() - 0.5); ry = y + dy*(randgen() - 0.5); rz = z + dz*(randgen() - 0.5); } else { rx = x; ry = y; rz = z; } // to world space MPoint pt( rx, ry, rz ); pt *= fluidWorldMatrix; // test to see if point is inside volume primitive // if( volumePrimitivePointInside( pt, emitterWorldMatrix ) ) { // compute dropoff // double dist = pt.distanceTo( emitterPos ); double distDrop = dropoff * (dist*dist); double newVal = (theRate * exp( -distDrop )) / (double)numSamples; // emit into arrays // if( newVal != 0.0 ) { fluid.emitIntoArrays( (float) newVal, i, j, k, (float)densityEmit, (float)heatEmit, (float)fuelEmit, doEmitColor, emitColor ); } } } } } } }
virtual void ExportProcedural( AtNode *node ) { // do basic node export ExportMatrix( node, 0 ); // AiNodeSetPtr( node, "shader", arnoldShader(node) ); AiNodeSetInt( node, "visibility", ComputeVisibility() ); MPlug plug = FindMayaObjectPlug( "receiveShadows" ); if( !plug.isNull() ) { AiNodeSetBool( node, "receive_shadows", plug.asBool() ); } plug = FindMayaObjectPlug( "aiSelfShadows" ); if( !plug.isNull() ) { AiNodeSetBool( node, "self_shadows", plug.asBool() ); } plug = FindMayaObjectPlug( "aiOpaque" ); if( !plug.isNull() ) { AiNodeSetBool( node, "opaque", plug.asBool() ); } // now set the procedural-specific parameters AiNodeSetBool( node, "load_at_init", true ); // just for now so that it can load the shaders at the right time MFnDagNode fnDagNode( m_dagPath ); MBoundingBox bound = fnDagNode.boundingBox(); AiNodeSetPnt( node, "min", bound.min().x-m_dispPadding, bound.min().y-m_dispPadding, bound.min().z-m_dispPadding ); AiNodeSetPnt( node, "max", bound.max().x+m_dispPadding, bound.max().y, bound.max().z+m_dispPadding ); const char *dsoPath = getenv( "ALEMBIC_ARNOLD_PROCEDURAL_PATH" ); AiNodeSetStr( node, "dso", dsoPath ? dsoPath : "bb_AlembicArnoldProcedural.so" ); // Set the parameters for the procedural //abcFile path MString abcFile = fnDagNode.findPlug("cacheFileName").asString().expandEnvironmentVariablesAndTilde(); //object path MString objectPath = fnDagNode.findPlug("cacheGeomPath").asString(); //object pattern MString objectPattern = "*"; plug = FindMayaObjectPlug( "objectPattern" ); if (!plug.isNull() ) { if (plug.asString() != "") { objectPattern = plug.asString(); } } //object pattern MString excludePattern = ""; plug = FindMayaObjectPlug( "excludePattern" ); if (!plug.isNull() ) { if (plug.asString() != "") { excludePattern = plug.asString(); } } float shutterOpen = 0.0; plug = FindMayaObjectPlug( "shutterOpen" ); if (!plug.isNull() ) { shutterOpen = plug.asFloat(); } float shutterClose = 0.0; plug = FindMayaObjectPlug( "shutterClose" ); if (!plug.isNull() ) { shutterClose = plug.asFloat(); } float timeOffset = 0.0; plug = FindMayaObjectPlug( "timeOffset" ); if (!plug.isNull() ) { timeOffset = plug.asFloat(); } int subDIterations = 0; plug = FindMayaObjectPlug( "ai_subDIterations" ); if (!plug.isNull() ) { subDIterations = plug.asInt(); } MString nameprefix = ""; plug = FindMayaObjectPlug( "namePrefix" ); if (!plug.isNull() ) { nameprefix = plug.asString(); } // bool exportFaceIds = fnDagNode.findPlug("exportFaceIds").asBool(); bool makeInstance = true; // always on for now plug = FindMayaObjectPlug( "makeInstance" ); if (!plug.isNull() ) { makeInstance = plug.asBool(); } bool flipv = false; plug = FindMayaObjectPlug( "flipv" ); if (!plug.isNull() ) { flipv = plug.asBool(); } bool invertNormals = false; plug = FindMayaObjectPlug( "invertNormals" ); if (!plug.isNull() ) { invertNormals = plug.asBool(); } short i_subDUVSmoothing = 1; plug = FindMayaObjectPlug( "ai_subDUVSmoothing" ); if (!plug.isNull() ) { i_subDUVSmoothing = plug.asShort(); } MString subDUVSmoothing; switch (i_subDUVSmoothing) { case 0: subDUVSmoothing = "pin_corners"; break; case 1: subDUVSmoothing = "pin_borders"; break; case 2: subDUVSmoothing = "linear"; break; case 3: subDUVSmoothing = "smooth"; break; default : subDUVSmoothing = "pin_corners"; break; } MTime curTime = MAnimControl::currentTime(); // fnDagNode.findPlug("time").getValue( frame ); // MTime frameOffset; // fnDagNode.findPlug("timeOffset").getValue( frameOffset ); float time = curTime.as(MTime::kFilm)+timeOffset; MString argsString; if (objectPath != "|"){ argsString += "-objectpath "; // convert "|" to "/" argsString += MString(replace_all(objectPath,"|","/").c_str()); } if (objectPattern != "*"){ argsString += "-pattern "; argsString += objectPattern; } if (excludePattern != ""){ argsString += "-excludepattern "; argsString += excludePattern; } if (shutterOpen != 0.0){ argsString += " -shutteropen "; argsString += shutterOpen; } if (shutterClose != 0.0){ argsString += " -shutterclose "; argsString += shutterClose; } if (subDIterations != 0){ argsString += " -subditerations "; argsString += subDIterations; argsString += " -subduvsmoothing "; argsString += subDUVSmoothing; } if (makeInstance){ argsString += " -makeinstance "; } if (nameprefix != ""){ argsString += " -nameprefix "; argsString += nameprefix; } if (flipv){ argsString += " -flipv "; } if (invertNormals){ argsString += " -invertNormals "; } argsString += " -filename "; argsString += abcFile; argsString += " -frame "; argsString += time; if (m_displaced){ argsString += " -disp_map "; argsString += AiNodeGetName(m_dispNode); } AiNodeSetStr(node, "data", argsString.asChar()); ExportUserAttrs(node); // Export light linking per instance ExportLightLinking(node); }
// write the frame ranges and statistic string on the root // Also call the post callbacks void AbcWriteJob::postCallback(double iFrame) { std::string statsStr = ""; addToString(statsStr, "SubDStaticNum", mStats.mSubDStaticNum); addToString(statsStr, "SubDAnimNum", mStats.mSubDAnimNum); addToString(statsStr, "SubDStaticCVs", mStats.mSubDStaticCVs); addToString(statsStr, "SubDAnimCVs", mStats.mSubDAnimCVs); addToString(statsStr, "SubDStaticFaces", mStats.mSubDStaticFaces); addToString(statsStr, "SubDAnimFaces", mStats.mSubDAnimFaces); addToString(statsStr, "PolyStaticNum", mStats.mPolyStaticNum); addToString(statsStr, "PolyAnimNum", mStats.mPolyAnimNum); addToString(statsStr, "PolyStaticCVs", mStats.mPolyStaticCVs); addToString(statsStr, "PolyAnimCVs", mStats.mPolyAnimCVs); addToString(statsStr, "PolyStaticFaces", mStats.mPolyStaticFaces); addToString(statsStr, "PolyAnimFaces", mStats.mPolyAnimFaces); addToString(statsStr, "CurveStaticNum", mStats.mCurveStaticNum); addToString(statsStr, "CurveStaticCurves", mStats.mCurveStaticCurves); addToString(statsStr, "CurveAnimNum", mStats.mCurveAnimNum); addToString(statsStr, "CurveAnimCurves", mStats.mCurveAnimCurves); addToString(statsStr, "CurveStaticCVs", mStats.mCurveStaticCVs); addToString(statsStr, "CurveAnimCVs", mStats.mCurveAnimCVs); addToString(statsStr, "PointStaticNum", mStats.mPointStaticNum); addToString(statsStr, "PointAnimNum", mStats.mPointAnimNum); addToString(statsStr, "PointStaticCVs", mStats.mPointStaticCVs); addToString(statsStr, "PointAnimCVs", mStats.mPointAnimCVs); addToString(statsStr, "NurbsStaticNum", mStats.mNurbsStaticNum); addToString(statsStr, "NurbsAnimNum", mStats.mNurbsAnimNum); addToString(statsStr, "NurbsStaticCVs", mStats.mNurbsStaticCVs); addToString(statsStr, "NurbsAnimCVs", mStats.mNurbsAnimCVs); addToString(statsStr, "TransStaticNum", mStats.mTransStaticNum); addToString(statsStr, "TransAnimNum", mStats.mTransAnimNum); addToString(statsStr, "LocatorStaticNum", mStats.mLocatorStaticNum); addToString(statsStr, "LocatorAnimNum", mStats.mLocatorAnimNum); addToString(statsStr, "CameraStaticNum", mStats.mCameraStaticNum); addToString(statsStr, "CameraAnimNum", mStats.mCameraAnimNum); if (statsStr.length() > 0) { Alembic::Abc::OStringProperty stats(mRoot.getTop().getProperties(), "statistics"); stats.set(statsStr); } if (mTransTimeIndex != 0) { MString propName; propName += static_cast<int>(mTransTimeIndex); propName += ".samples"; Alembic::Abc::OUInt32Property samp(mRoot.getTop().getProperties(), propName.asChar()); samp.set(mTransSamples); } if (mShapeTimeIndex != 0 && mShapeTimeIndex != mTransTimeIndex) { MString propName; propName += static_cast<int>(mShapeTimeIndex); propName += ".samples"; Alembic::Abc::OUInt32Property samp(mRoot.getTop().getProperties(), propName.asChar()); samp.set(mShapeSamples); } MBoundingBox bbox; if (mArgs.melPostCallback.find("#BOUNDS#") != std::string::npos || mArgs.pythonPostCallback.find("#BOUNDS#") != std::string::npos || mArgs.melPostCallback.find("#BOUNDSARRAY#") != std::string::npos || mArgs.pythonPostCallback.find("#BOUNDSARRAY#") != std::string::npos) { util::ShapeSet::const_iterator it = mArgs.dagPaths.begin(); const util::ShapeSet::const_iterator end = mArgs.dagPaths.end(); for (; it != end; it ++) { mCurDag = *it; MMatrix eMInvMat; if (mArgs.worldSpace) { eMInvMat.setToIdentity(); } else { eMInvMat = mCurDag.exclusiveMatrixInverse(); } bbox.expand(getBoundingBox(iFrame, eMInvMat)); } } processCallback(mArgs.melPostCallback, true, iFrame, bbox); processCallback(mArgs.pythonPostCallback, false, iFrame, bbox); }
MBoundingBox AbcWriteJob::getBoundingBox(double iFrame, const MMatrix & eMInvMat) { MStatus status; MBoundingBox curBBox; if (iFrame == mFirstFrame) { // Set up bbox shape map in the first frame. // If we have a lot of transforms and shapes, we don't need to // iterate them for each frame. MItDag dagIter; for (dagIter.reset(mCurDag); !dagIter.isDone(); dagIter.next()) { MObject object = dagIter.currentItem(); MDagPath path; dagIter.getPath(path); // short-circuit if the selection flag is on but this node is not in the // active selection // MGlobal::isSelected(ob) doesn't work, because DG node and DAG node is // not the same even if they refer to the same MObject if (mArgs.useSelectionList && !mSList.hasItem(path)) { dagIter.prune(); continue; } MFnDagNode dagNode(path, &status); if (status == MS::kSuccess) { // check for riCurves flag for flattening all curve object to // one curve group MPlug riCurvesPlug = dagNode.findPlug("riCurves", &status); if ( status == MS::kSuccess && riCurvesPlug.asBool() == true) { MBoundingBox box = dagNode.boundingBox(); box.transformUsing(path.exclusiveMatrix()*eMInvMat); curBBox.expand(box); // Prune this curve group dagIter.prune(); // Save children paths std::map< MDagPath, util::ShapeSet, util::cmpDag >::iterator iter = mBBoxShapeMap.insert(std::make_pair(mCurDag, util::ShapeSet())).first; if (iter != mBBoxShapeMap.end()) (*iter).second.insert(path); } else if (object.hasFn(MFn::kParticle) || object.hasFn(MFn::kMesh) || object.hasFn(MFn::kNurbsCurve) || object.hasFn(MFn::kNurbsSurface) ) { if (util::isIntermediate(object)) continue; MBoundingBox box = dagNode.boundingBox(); box.transformUsing(path.exclusiveMatrix()*eMInvMat); curBBox.expand(box); // Save children paths std::map< MDagPath, util::ShapeSet, util::cmpDag >::iterator iter = mBBoxShapeMap.insert(std::make_pair(mCurDag, util::ShapeSet())).first; if (iter != mBBoxShapeMap.end()) (*iter).second.insert(path); } } } } else { // We have already find out all the shapes for the dag path. std::map< MDagPath, util::ShapeSet, util::cmpDag >::iterator iter = mBBoxShapeMap.find(mCurDag); if (iter != mBBoxShapeMap.end()) { // Iterate through the saved paths to calculate the box. util::ShapeSet& paths = (*iter).second; for (util::ShapeSet::iterator pathIter = paths.begin(); pathIter != paths.end(); pathIter++) { MFnDagNode dagNode(*pathIter, &status); if (status == MS::kSuccess) { MBoundingBox box = dagNode.boundingBox(); box.transformUsing((*pathIter).exclusiveMatrix()*eMInvMat); curBBox.expand(box); } } } } return curBBox; }