Writing an Atoms graph node
You can create custom dependency graph nodes, which carry out custom operations based on their incoming data. Each node type you write can be added to the agent dependency graph.
This is an example of a node that returns the intersection between a ray and an height field.
#include <AtomsGraph/Globals.h> #include <Atoms/Globals.h> #include <AtomsGraph/Ports.h> #include <AtomsGraph/NodeFactory.h> #include <Atoms/HeightFields.h> #include <Atoms/HeightField.h> class HeighFieldIntersectorNode: public AtomsGraph::Node { public: NODE_STANDARD_MEMBERS HeighFieldIntersectorNode(); virtual ~HeighFieldIntersectorNode(); virtual bool compute(); private: AtomsGraph::StringPort *m_heightFieldNamePort; AtomsGraph::VectorPort *m_rayOriginPort; AtomsGraph::VectorPort *m_rayDirectionPort; AtomsGraph::VectorPort *m_outPositionPort; AtomsGraph::VectorPort *m_outNormalPort; }; #define HEIGHTFIELDINTERSECTOR_NODE_ID 999999 // this must be unique NODE_STANDARD_MEMBERS_IMPL(HeighFieldIntersectorNode) unsigned int HeighFieldIntersectorNode::staticTypeId() { return HEIGHTFIELDINTERSECTOR_NODE_ID; } std::string HeighFieldIntersectorNode::staticTypeStr() { return std::string("HeighFieldIntersectorNode");} HeighFieldIntersectorNode::HeighFieldIntersectorNode() { m_heightFieldNamePort = new AtomsGraph::StringPort("heightField"); m_rayOriginPort = new AtomsGraph::VectorPort("rayOrigin"); m_rayDirectionPort = new AtomsGraph::VectorPort("rayDirection"); m_outPositionPort = new AtomsGraph::VectorPort("outPosition"); m_outNormalPort = new AtomsGraph::VectorPort("outNormal"); // add input and output ports addInputPort(m_heightFieldNamePort); addInputPort(m_rayOriginPort); addInputPort(m_rayDirectionPort); addOutputPort(m_outPositionPort); addOutputPort(m_outNormalPort); } HeighFieldIntersectorNode::~HeighFieldIntersectorNode() { // the parent destructor automatically deletes all the ports so we don't need to delete them here } bool HeighFieldIntersectorNode::compute() { Atoms::HeightFields& fields = Atoms::HeightFields::instance(); // get the height field name from the input port const std::string& heightFieldName = heightFieldNamePort->getRef(); // check if the height field exist AtomsUtils::Mesh* heightField = fields.heightField(heightFieldName); if (!heightField) return false; float param, u, v; unsigned int faceId = 0; // compute the intersection if (heightField->intersect(rayOriginPort->getRef(), m_rayDirectionPort->getRef(), param, faceId, u, v, false)) { AtomsCore::Vector3 projectedPos = rayOriginPort->getRef() + double(param) * m_rayDirectionPort->getRef(); // compute the normal from the barycentric coords of the intersection std::vector<AtomsCore::Vector3f> &normals = heightField->normals(); AtomsCore::Vector3 hfNormal = u * normals[faceId * 3] + v * normals[faceId * 3 + 1] + (1.0f - u - v) * normals[faceId * 3 + 2]; hfNormal.normalize(); // set the output ports m_outPositionPort->set(projectedPos); m_outNormalPort->set(hfNormal); } return true; } extern "C" { ATOMSPLUGIN_EXPORT bool initializePlugin() { AtomsUtils::Logger::info() << "Loading HeighFieldIntersectorNode plugin"; // Register the node to the factory AtomsGraph::NodeFactory& manager = AtomsGraph::NodeFactory::instance(); manager.registerNode(HeighFieldIntersectorNode::staticTypeStr(), &HeighFieldIntersectorNode::creator); return true; } ATOMSPLUGIN_EXPORT bool unitializePlugin() { AtomsUtils::Logger::info() << "Unloading HeighFieldIntersectorNode plugin"; // Deregister the node from the node factory AtomsGraph::NodeFactory& manager = AtomsGraph::NodeFactory::instance(); manager.deregisterNode(HeighFieldIntersectorNode::staticTypeStr()); return true; } }
Copyright © 2017, Toolchefs LTD.