// ****************************************************************** // Rekursive Sichtbarkeitsberechnung void tbOctree::ComputeVisibility(tbOctreeNode* pNode, tbPlane* pViewFrustum, tbVector3 vCamera, BOOL bDepthSort) { // Wenn der Knoten unsichtbar ist, brechen wir sofort ab. if(!tbAABoxVisible(pNode->vBoundingBoxMin, pNode->vBoundingBoxMax, pViewFrustum)) return; if(pNode->bIsLeaf) { // Den Knoten als sichtbar eintragen m_ppVisibleList[m_dwNumLeavesVisible] = pNode; m_dwNumLeavesVisible++; // Wenn nach Tiefe sortiert werden soll, dann berechnen wir noch das // Quadrat der Entfernung der Mitte des Knotens zur Kamera. if(bDepthSort) { pNode->fDistSq = tbVector3LengthSq((0.5f * (pNode->vBoundingBoxMin + pNode->vBoundingBoxMax)) - vCamera); } } else { for(int i = 0; i < 8; i++) { // Sichtbarkeit dieses Unterknotens testen ComputeVisibility(pNode->apChild[i], pViewFrustum, vCamera, bDepthSort); } } }
// ****************************************************************** // Diese Methode rendert den Octree. tbResult tbOctree::Render(tbPlane* pViewFrustum, tbVector3 vCamera, int iFrom, // = -1 int iTo, // = -1 BOOL bRenderOpaque, // = TRUE BOOL bRenderAlphaBlended, // = TRUE BOOL bDepthSort) // = TRUE { HRESULT hResult; DWORD dwOldFVF; int iNumPasses; tbOctreeNode* pLeaf; // Parameter prüfen if(iFrom < -1 || iFrom >= (int)(m_dwNumEffects)) TB_ERROR_INVALID_VALUE("iFrom", TB_ERROR); if(iTo < -1 || iTo >= (int)(m_dwNumEffects)) TB_ERROR_INVALID_VALUE("iTo", TB_ERROR); // Werte anpassen if(iFrom == -1) iFrom = 0; if(iTo == -1) iTo = m_dwNumEffects - 1; // Sichtbarkeitsliste erstellen m_dwNumLeavesVisible = 0; ComputeVisibility(m_pRootNode, pViewFrustum, vCamera, bDepthSort); // Wenn erwünscht, nach Tiefe sortieren if(bDepthSort) qsort(m_ppVisibleList, m_dwNumLeavesVisible, sizeof(tbOctreeNode*), LeafCmpFunc); // Altes Vertexformat speichern dwOldFVF = tbDirect3D::GetFVF(); // Vertexformat so wie Vertex- und Index-Buffer setzen tbDirect3D::SetFVF(m_dwFVF); tbDirect3D::GetDevice()->SetStreamSource(0, m_pVertexBuffer->GetVB(), 0, m_pVertexBuffer->GetVertexSize()); tbDirect3D::GetDevice()->SetIndices(m_pIndexBuffer->GetIB()); // Jeden Effekt durchgehen for(int iEffect = iFrom; iEffect <= iTo; iEffect++) { // Effekt aktivieren und alle Durchgänge rendern. // tbDirect3D::Capture wird später manuell aufgerufen. if(!m_pEffects[iEffect].Header.bAlphaBlended && bRenderOpaque || m_pEffects[iEffect].Header.bAlphaBlended && bRenderAlphaBlended) { iNumPasses = m_pEffects[iEffect].pEffect->Begin(TRUE, FALSE); for(int iPass = 0; iPass < iNumPasses; iPass++) { // Durchgang aktivieren m_pEffects[iEffect].pEffect->BeginPass(iPass); // Die Sichtbarkeitsliste rendern for(DWORD dwLeaf = 0; dwLeaf < m_dwNumLeavesVisible; dwLeaf++) { pLeaf = m_ppVisibleList[dwLeaf]; if(pLeaf->pdwEffectStart[iEffect] != 0xFFFFFFFF && pLeaf->pdwMinIndex[iEffect] != 0xFFFFFFFF && pLeaf->pdwMaxIndex[iEffect] != 0) { // Rendern if(FAILED(hResult = tbDirect3D::GetDevice()->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, pLeaf->pdwMinIndex[iEffect], pLeaf->pdwMaxIndex[iEffect] - pLeaf->pdwMinIndex[iEffect] + 1, pLeaf->pdwEffectStart[iEffect], (pLeaf->pdwEffectEnd[iEffect] - pLeaf->pdwEffectStart[iEffect]) / 3 + 1))) { // Fehler! m_pEffects[iEffect].pEffect->End(); TB_ERROR_DIRECTX("tbDirect3D::GetDevice()->DrawIndexedPrimitive", hResult, TB_ERROR); } } m_pEffects[iEffect].pEffect->EndPass(); } } // Effekt deaktivieren m_pEffects[iEffect].pEffect->End(); } } // Capture aufrufen, um die Tabellen in tbDirect3D zu aktualisieren tbDirect3D::Capture(); // Das alte Vertexformat wieder setzen tbDirect3D::SetFVF(dwOldFVF); return TB_OK; }
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(); } }
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); }