custom ice node and iceattributes

Discussions concerning programming of SOFTIMAGE©
nospitters
Posts: 47
Joined: 06 Jul 2012, 18:08
Location: bremen, germany

custom ice node and iceattributes

Post by nospitters » 24 Feb 2019, 11:37

hi,

i want to start creating custom ice nodes and for learning i want to create a simple one like a force node. for that i need to get the iceattributes generated by the pointcloud (mass, pointpositions,poinvelocities, etc).
can someone give me a hint how to get this iceattributes data and using it further in the custom ice node?
The Soulcage Department
http://www.soulcage-department.de

Pedrito
Posts: 35
Joined: 21 Feb 2018, 12:46
Location: Zaragoza,Spain

Re: custom ice node and iceattributes

Post by Pedrito » 25 Feb 2019, 10:49

Take a look at this, its a custom node you can test in my pc_Tools https://github.com/pedroCabrera/pcTools_Softimage. It accumulates values on a geometry attribute. Maybe this helps you!

// PC_Acum_Attribute
//Pedro Cabrera

#include <xsi_application.h>
#include <xsi_context.h>
#include <xsi_pluginregistrar.h>
#include <xsi_status.h>

#include <xsi_icenodecontext.h>
#include <xsi_icenodedef.h>
#include <xsi_command.h>
#include <xsi_factory.h>
#include <xsi_longarray.h>
#include <xsi_doublearray.h>
#include <xsi_math.h>
#include <xsi_vector2f.h>
#include <xsi_vector3f.h>
#include <xsi_vector4f.h>
#include <xsi_matrix3f.h>
#include <xsi_matrix4f.h>
#include <xsi_rotationf.h>
#include <xsi_quaternionf.h>
#include <xsi_color4f.h>
#include <xsi_icegeometry.h>
#include <xsi_iceportstate.h>
#include <xsi_indexset.h>
#include <xsi_dataarray.h>
#include <xsi_dataarray2D.h>
#include <xsi_geometry.h>
#include <xsi_x3dobject.h>
#include <xsi_ref.h>
#include <xsi_projectitem.h>
#include <xsi_primitive.h>

#include <xsi_iceattribute.h>
#include <xsi_iceattributedataarray.h>
#include <xsi_iceattributedataarray2D.h>
// Defines port, group and map identifiers used for registering the ICENode
enum IDs
{
ID_IN_Names = 0,
ID_IN_AttrName = 2,
ID_IN_AttrValue = 4,
ID_IN_Acum = 6,
ID_IN_Append = 8,
ID_G_100 = 100,
ID_OUT_ID = 200,
ID_TYPE_CNS = 400,
ID_STRUCT_CNS,
ID_CTXT_CNS,
ID_UNDEF = ULONG_MAX
};

using namespace XSI;



template < class T >
class AttributeDataAcum
{
public:
static bool Do( ICEAttribute& attr ,ICENodeContext& in_ctxt, ULONG in_nInPortID,XSI::siICENodeStructureType in_outStruct,bool acum,bool append)
{
if ( in_outStruct == XSI::siICENodeStructureSingle )
{
CICEAttributeDataArray< T > data;
attr.GetDataArray( data );

CDataArray<T> inData( in_ctxt,in_nInPortID );
CIndexSet indexSet( in_ctxt ,in_nInPortID);

ULONG l_nbElem = attr.GetElementCount();
//Application().LogMessage(CString(l_nbElem));
T* l_Values = new T[l_nbElem];
for(CIndexSet::Iterator i = indexSet.Begin(); i<l_nbElem && i.HasNext(); i.Next()){
if(acum)
l_Values[i.GetIndex()]=data[i.GetIndex()]+ inData;
else
l_Values[i.GetIndex()]=inData;
}
return(data.SetArray(l_Values, l_nbElem)==CStatus::OK);
}
else if ( in_outStruct == XSI::siICENodeStructureArray )
{
CICEAttributeDataArray2D< T > data2D;
attr.GetDataArray2D( data2D );

CDataArray2D<T> inData( in_ctxt,in_nInPortID );
CIndexSet indexSet( in_ctxt ,in_nInPortID);

ULONG l_nbElem = attr.GetElementCount();
T** l_Values = new T*[l_nbElem];
ULONG* subArraySizes = new ULONG[l_nbElem];

for(CIndexSet::Iterator i = indexSet.Begin(); i<l_nbElem && i.HasNext(); i.Next())
{
CDataArray2D<T>::Accessor insubArray = inData;
if(acum){
CICEAttributeDataArray<T> data;
data2D.GetSubArray(i,data);
if(!append){
T* sub = new T[data.GetCount()];
for (ULONG e=0;e<data.GetCount();e++)
sub[e]=data[e]+insubArray[e<insubArray.GetCount()?e:insubArray.GetCount()-1];
l_Values[i.GetIndex()] = sub;
subArraySizes[i.GetIndex()] = data.GetCount();
}else{
T* sub = new T[data.GetCount()+insubArray.GetCount()];
for (ULONG e=0;e<data.GetCount();e++)
sub[e]=data[e];
for (ULONG e=0;e<insubArray.GetCount();e++)
sub[e+data.GetCount()]=insubArray[e];
l_Values[i.GetIndex()] = sub;
subArraySizes[i.GetIndex()] = data.GetCount()+insubArray.GetCount();
}

}else{
T* sub = new T[insubArray.GetCount()];;
for (ULONG e=0;e<insubArray.GetCount();e++)
sub[e]=insubArray[e];
l_Values[i.GetIndex()] = sub;
subArraySizes[i.GetIndex()] = insubArray.GetCount();
}
}
return(data2D.SetArray2D((const T**)l_Values, l_nbElem, subArraySizes)==CStatus::OK);
}
}

};
template < >
class AttributeDataAcum< XSI::CString>
{
public:
static void Do( ICEAttribute& attr ,ICENodeContext& in_ctxt, ULONG in_nInPortID,XSI::siICENodeStructureType in_outStruct,bool acum,bool append)
{
if ( in_outStruct == XSI::siICENodeStructureSingle )
{
CICEAttributeDataArrayString data;
attr.GetDataArray( data );

CDataArrayString inData( in_ctxt,in_nInPortID );
CIndexSet indexSet( in_ctxt ,in_nInPortID);

ULONG l_nbElem = attr.GetElementCount();
for(CIndexSet::Iterator i = indexSet.Begin(); i<l_nbElem && i.HasNext(); i.Next())
data.SetData(i,inData);
}
else if ( in_outStruct == XSI::siICENodeStructureArray )
{
CICEAttributeDataArray2DString data2D;
attr.GetDataArray2D( data2D );

CDataArray2DString inData( in_ctxt,in_nInPortID );
CIndexSet indexSet( in_ctxt ,in_nInPortID);

ULONG l_nbElem = attr.GetElementCount();
for(CIndexSet::Iterator i = indexSet.Begin(); i<l_nbElem && i.HasNext(); i.Next())
{
CDataArray2DString::Accessor insubArray = inData;
CICEAttributeDataArrayString data;
data2D.ResizeSubArray( i ,insubArray.GetCount() ,data );
for (ULONG e=0;e<insubArray.GetCount();e++)
data.SetData(e,insubArray[e]);
}
}
}

};

template < class T >
class AttributeDataAcumVec
{
public:
static bool Do( ICEAttribute& attr ,ICENodeContext& in_ctxt, ULONG in_nInPortID,XSI::siICENodeStructureType in_outStruct,bool acum,bool append)
{
if ( in_outStruct == XSI::siICENodeStructureSingle )
{
CICEAttributeDataArray< T > data;
attr.GetDataArray( data );

CDataArray<T> inData( in_ctxt,in_nInPortID );
CIndexSet indexSet( in_ctxt ,in_nInPortID);

ULONG l_nbElem = attr.GetElementCount();
//Application().LogMessage(CString(l_nbElem));
T* l_Values = new T[l_nbElem];
for(CIndexSet::Iterator i = indexSet.Begin(); i<l_nbElem && i.HasNext(); i.Next()){
if(acum)
l_Values[i.GetIndex()]=data[i.GetIndex()].AddInPlace(inData);
else
l_Values[i.GetIndex()]=inData;
}
return(data.SetArray(l_Values, l_nbElem)==CStatus::OK);
}
else if ( in_outStruct == XSI::siICENodeStructureArray )
{
CICEAttributeDataArray2D< T > data2D;
attr.GetDataArray2D( data2D );

CDataArray2D<T> inData( in_ctxt,in_nInPortID );
CIndexSet indexSet( in_ctxt ,in_nInPortID);

ULONG l_nbElem = attr.GetElementCount();
T** l_Values = new T*[l_nbElem];
ULONG* subArraySizes = new ULONG[l_nbElem];

for(CIndexSet::Iterator i = indexSet.Begin(); i<l_nbElem && i.HasNext(); i.Next())
{
CDataArray2D<T>::Accessor insubArray = inData;
if(acum){
CICEAttributeDataArray<T> data;
data2D.GetSubArray(i,data);
if(!append){
T* sub = new T[data.GetCount()];
for (ULONG e=0;e<data.GetCount();e++)
sub[e]=data[e].AddInPlace(insubArray[e<insubArray.GetCount()?e:insubArray.GetCount()-1]);
l_Values[i.GetIndex()] = sub;
subArraySizes[i.GetIndex()] = data.GetCount();
}else{
T* sub = new T[data.GetCount()+insubArray.GetCount()];
for (ULONG e=0;e<data.GetCount();e++)
sub[e]=data[e];
for (ULONG e=0;e<insubArray.GetCount();e++)
sub[e+data.GetCount()]=insubArray[e];
l_Values[i.GetIndex()] = sub;
subArraySizes[i.GetIndex()] = data.GetCount()+insubArray.GetCount();
}

}else{
T* sub = new T[insubArray.GetCount()];;
for (ULONG e=0;e<insubArray.GetCount();e++)
sub[e]=insubArray[e];
l_Values[i.GetIndex()] = sub;
subArraySizes[i.GetIndex()] = insubArray.GetCount();
}
}
return(data2D.SetArray2D((const T**)l_Values, l_nbElem, subArraySizes)==CStatus::OK);
}
}

};


CStatus RegisterPC_Acumulate_Attribute( PluginRegistrar& in_reg )
{
ICENodeDef nodeDef;
nodeDef = Application().GetFactory().CreateICENodeDef(L"PC_Acumulate_Attribute",L"PC_Acumulate Attribute");

CStatus st;
st = nodeDef.PutColor(117, 176, 193);
st.AssertSucceeded( ) ;

st = nodeDef.PutThreadingModel(XSI::siICENodeSingleThreading );
st.AssertSucceeded( ) ;

// Add input ports and groups.
st = nodeDef.AddPortGroup(ID_G_100);
st.AssertSucceeded( ) ;

st = nodeDef.AddInputPort(ID_IN_Acum,ID_G_100,siICENodeDataBool,siICENodeStructureSingle,siICENodeContextSingleton ,L"Acum",L"Acum",L"",CValue(),CValue(),ID_UNDEF,ID_UNDEF,ID_UNDEF);
st.AssertSucceeded( ) ;
st = nodeDef.AddInputPort(ID_IN_Append,ID_G_100,siICENodeDataBool,siICENodeStructureSingle,siICENodeContextSingleton ,L"Append",L"Append",L"",CValue(),CValue(),ID_UNDEF,ID_UNDEF,ID_UNDEF);
st.AssertSucceeded( ) ;

st = nodeDef.AddInputPort(ID_IN_Names,ID_G_100,siICENodeDataString,siICENodeStructureSingle,siICENodeContextSingleton ,L"Object",L"Object",L"",CValue(),CValue(),ID_UNDEF,ID_UNDEF,ID_UNDEF);
st.AssertSucceeded( ) ;
st = nodeDef.AddInputPort(ID_IN_AttrName,ID_G_100,siICENodeDataString,siICENodeStructureSingle,siICENodeContextSingleton ,L"Attribute",L"Attribute",L"",CValue(),CValue(),ID_UNDEF,ID_UNDEF,ID_UNDEF);
st.AssertSucceeded( ) ;
st = nodeDef.AddInputPort(ID_IN_AttrValue,ID_G_100,siICENodeDataAny,siICENodeStructureAny,siICENodeContextAny ,L"Data",L"Data",L"",CValue(),CValue(),ID_UNDEF,ID_UNDEF,ID_UNDEF);
st.AssertSucceeded( ) ;

// Add output ports.
st = nodeDef.AddOutputPort(ID_OUT_ID,siICENodeDataBool,siICENodeStructureSingle,siICENodeContextSingleton ,L"Success",L"Success",ID_UNDEF,ID_UNDEF,ID_UNDEF);
st.AssertSucceeded( ) ;

PluginItem nodeItem = in_reg.RegisterICENode(nodeDef);
nodeItem.PutCategories(L"PC_Tools/PC_Cpp,PC_Tools/PC_Cpp");

return CStatus::OK;
}

SICALLBACK PC_Acumulate_Attribute_Evaluate( ICENodeContext& in_ctxt )
{
// The current output port being evaluated...
ULONG out_portID = in_ctxt.GetEvaluatedOutputPortID( );
switch( out_portID )
{
case ID_OUT_ID :
{
// Get the output port array ...
CDataArrayBool outData( in_ctxt );
bool success = true;
try{
siICENodeDataType in_datatype;
siICENodeStructureType in_struct;
siICENodeContextType in_context;
in_ctxt.GetPortInfo( ID_IN_AttrValue, in_datatype, in_struct, in_context );

//MATH::CMatrix3f s;
//s.AddInPlace(s);

CDataArrayString NamesSubArray( in_ctxt, ID_IN_Names );
CDataArrayString AttrSubArray( in_ctxt, ID_IN_AttrName );
CDataArrayBool acumSubArray(in_ctxt, ID_IN_Acum);
CDataArrayBool appendSubArray(in_ctxt, ID_IN_Append);

bool acum = acumSubArray[0];
bool append = appendSubArray[0];
CRef ObjectRef;
ObjectRef.Set(NamesSubArray[0]);
ObjectRef.IsValid();
X3DObject obj(ObjectRef);
Geometry geom(obj.GetActivePrimitive().GetGeometry(0) );
success = ObjectRef.IsValid() && obj.IsValid()&& geom.IsValid();
ICEAttribute attr = geom.GetICEAttributeFromName(AttrSubArray[0]);
Application().LogMessage("indata type ="+CString(in_datatype)+ "attrdata type="+CString(attr.GetDataType()));
Application().LogMessage("indata struct ="+CString(in_struct)+ "attrdata struct="+CString(attr.GetStructureType()));
Application().LogMessage("indata ctxt ="+CString(in_context)+ "attrdata ctxt="+CString(attr.GetContextType()));
Application().LogMessage(CString(in_datatype!=attr.GetDataType() || in_struct!=attr.GetStructureType() || in_context!=attr.GetContextType()));
if(attr.GetName().Length()==0)
attr = geom.AddICEAttribute(AttrSubArray[0],in_datatype ,in_struct , in_context);
else if(in_datatype!=attr.GetDataType() || in_struct!=attr.GetStructureType() || in_context!=attr.GetContextType())
{
geom.RemoveICEAttribute(AttrSubArray[0]);
attr = geom.AddICEAttribute(AttrSubArray[0],in_datatype ,in_struct , in_context);
}
switch (in_datatype)
{
case siICENodeDataString: AttributeDataAcum<XSI::CString>::Do( attr, in_ctxt,ID_IN_AttrValue, in_struct ,acum,append); break;
case siICENodeDataFloat: success = AttributeDataAcum<float>::Do( attr, in_ctxt,ID_IN_AttrValue, in_struct ,acum,append); break;
case siICENodeDataLong: success = AttributeDataAcum<LONG>::Do( attr, in_ctxt, ID_IN_AttrValue, in_struct ,acum,append); break;
case siICENodeDataBool: success = AttributeDataAcum<bool>::Do( attr ,in_ctxt, ID_IN_AttrValue, in_struct ,acum,append); break;
case siICENodeDataVector2: success = AttributeDataAcumVec<MATH::CVector2f>::Do( attr, in_ctxt, ID_IN_AttrValue, in_struct,acum,append ); break;
case siICENodeDataVector3: success = AttributeDataAcumVec<MATH::CVector3f>::Do( attr, in_ctxt, ID_IN_AttrValue, in_struct,acum,append ); break;
case siICENodeDataVector4: success = AttributeDataAcumVec<MATH::CVector4f>::Do( attr, in_ctxt, ID_IN_AttrValue, in_struct ,acum,append); break;
case siICENodeDataQuaternion: success = AttributeDataAcumVec<MATH::CQuaternionf>::Do( attr, in_ctxt, ID_IN_AttrValue, in_struct ,acum,append); break;
//case siICENodeDataRotation: success = AttributeDataAcumVec<MATH::CRotationf>::Do( attr, in_ctxt, ID_IN_AttrValue, in_struct ,acum,append); break;
//case siICENodeDataMatrix33: success = AttributeDataAcumVec<MATH::CMatrix3f>::Do( attr, in_ctxt, ID_IN_AttrValue, in_struct ,acum,append); break;
//case siICENodeDataMatrix44: success = AttributeDataAcumVec<MATH::CMatrix4f>::Do( attr, in_ctxt, ID_IN_AttrValue, in_struct ,acum,append); break;
//case siICENodeDataColor4: success = AttributeDataAcumVec<MATH::CColor4f>::Do( attr, in_ctxt, ID_IN_AttrValue, in_struct ,acum,append); break;
//case siICENodeDataShape: success = AttributeDataSeter<MATH::CShape>::Do( attr, in_ctxt, ID_IN_AttrValue, in_struct ); break;
//case siICENodeDataCustomType: AttributeDataSeter<CDataArrayCustomType::TData>::Do( attr, in_ctxt, ID_IN_AttrValue, in_struct ); break;
};

}
catch(...){
success = false;
}
outData.Set(0,success);
}
break;

// Other output ports...
};

return CStatus::OK;
}

nospitters
Posts: 47
Joined: 06 Jul 2012, 18:08
Location: bremen, germany

Re: custom ice node and iceattributes

Post by nospitters » 25 Feb 2019, 13:50

hi pedro,

thanx for the sample code. but for some reason i dont get any values from the ice attributes.
dont know if its getting the right geometry, the one the custom ice node sits on...
here is my code:

Code: Select all

template < class T >
class CICEAttributeDataLogger
{
public:
	static void Log(ICEAttribute& attr)
	{
		CICEAttributeDataArray< T > data;
		attr.GetDataArray(data);

		Application xsi;
		for (ULONG i = 0; i<data.GetCount(); i++)
		{
			xsi.LogMessage(CString(data[i]));
		}
	}
};

SICALLBACK SimpleGravity_Evaluate( ICENodeContext& in_ctxt )
{
	// The current output port being evaluated...
	ULONG out_portID = in_ctxt.GetEvaluatedOutputPortID( );
  
	switch( out_portID )
	{		
		case ID_OUT_OutPort :
		{
			// Get the output port array ...			
			CDataArrayVector3f outData( in_ctxt );
			
 			// Get the input data buffers for each port
			CDataArrayVector3f PointPositionData( in_ctxt, ID_IN_PointPosition );
			CDataArrayVector3f ForceData( in_ctxt, ID_IN_Force );
			CRef ObjectRef;
			X3DObject obj(ObjectRef);
			Geometry geom(obj.GetActivePrimitive().GetGeometry(0));
			ICEAttribute pp = geom.GetICEAttributeFromName(L"PointPosition");

			CICEAttributeDataLogger<XSI::MATH::CVector3f>::Log(pp);


 			// We need a CIndexSet to iterate over the data 		
			CIndexSet indexSet( in_ctxt );
			for(CIndexSet::Iterator it = indexSet.Begin(); it.HasNext(); it.Next())
			{
				// Add code to set output port...
				
			}
		}
		break;
		
		// Other output ports...
	};
	
	return CStatus::OK;
}
The Soulcage Department
http://www.soulcage-department.de

Pedrito
Posts: 35
Joined: 21 Feb 2018, 12:46
Location: Zaragoza,Spain

Re: custom ice node and iceattributes

Post by Pedrito » 25 Feb 2019, 17:47

Can you try with another attribute , maybe PointPosition is protected... don't know. Also you are using " obj.GetActivePrimitive().GetGeometry(0)" this is not the object being evaluated i think

My code uses this, it call the geometry by name -- the "NamesSubarray[0]"

CRef ObjectRef;
ObjectRef.Set(NamesSubArray[0]);
ObjectRef.IsValid();
X3DObject obj(ObjectRef);
Geometry geom(obj.GetActivePrimitive().GetGeometry(0) );
success = ObjectRef.IsValid() && obj.IsValid()&& geom.IsValid();
ICEAttribute attr = geom.GetICEAttributeFromName(AttrSubArray[0]);

nospitters
Posts: 47
Joined: 06 Jul 2012, 18:08
Location: bremen, germany

Re: custom ice node and iceattributes

Post by nospitters » 25 Feb 2019, 18:15

i see. you provide the name by an in port...isnt it?
do you know a sdk function that is always getting the geometry where the ice node sits on? (in my case the pointcloud itsself, a so called "self.GetData()...)
The Soulcage Department
http://www.soulcage-department.de

Pedrito
Posts: 35
Joined: 21 Feb 2018, 12:46
Location: Zaragoza,Spain

Re: custom ice node and iceattributes

Post by Pedrito » 25 Feb 2019, 18:27

I will pash the geometry itself as a port, with a get data. self, and connect the geomtetry to a geometry input port
then you extract the attributes from that geo, don't think getting directly from the evaluation ice can work, you need to pass the geo itself or the name, one or another I think !

nospitters
Posts: 47
Joined: 06 Jul 2012, 18:08
Location: bremen, germany

Re: custom ice node and iceattributes

Post by nospitters » 25 Feb 2019, 19:09

ok. will try it with an in port and a get data "self"".

but hows the simulation particles node work, where there are no input ports but the data from the pointcloud is somewhere gets and sets and updated...?

(btw. isnt you thst was written this nvidia flex implementation in ICE? if yes, do think of making it public?)

greets.
The Soulcage Department
http://www.soulcage-department.de

Pedrito
Posts: 35
Joined: 21 Feb 2018, 12:46
Location: Zaragoza,Spain

Re: custom ice node and iceattributes

Post by Pedrito » 25 Feb 2019, 19:29

i Think simulation particles is a custom closed compound and not a pure c++ ice node, but anyway, propietary nodes have more acces than custom ones, take a look at the topology or location data, native nodes can use it, custom don't :S

Yes it will be public at some point, just to much work to do on it to consider it stable and releasable I think, if someone really interested in testing it out, contact me by private and we can talk about it!