Notifications
Clear all

[Closed] [SDK] Geometry object with proxy helper/shape/icon?

Hello,
Some geometry plugins like FumeFX, PointCloud, Particles etc. create a helper objecta at the clicking time that are displayed as lines. or shapes. So even if the mesh itdelf is not visible we always have this helper object, when clicked it has all the parameters.

So I wonder what is the right way to do it. For sure – I know that my plugin must be in Geomerty tab, so I don’t want to make a Helper Class. I think that I could just a geometry that will represent my plugin – but it can’t be visible during rendering and will appear in the viewport as filled geometry not lines.

Do you have any ideas?

Thanks in advance…

13 Replies

if it’s using simpleobject2 as the basis then you overide the display (and hittest) like this

int myobject::Display(TimeValue t, INode *inode, ViewExp *vpt, int flags)
{
	SimpleObject::Display(t, inode, vpt, flags); // call the simpleobject routine to display the actual geometry

// my drawing routines go here
	

	return 0;
}

and hit test something like

int	myobject::HitTest(TimeValue t, INode *inode, int type, int crossing, int flags, IPoint2 *p, ViewExp *vpt)
{
// get our hit here, if we have one return it otherwize fall through to the default handler	

	return SimpleObject::HitTest(t,inode,type,crossing,flags,p,vpt);
}

there are issues that I never found a solution for, that if a modifier is applied the our draw call is never made so we lose our gizmo (seems to be ok for particles though )

oh and you also have to update the bounding box routines as well or you can get update issues

Thanks again for answers Klvnk

I am still wondering about making this icon as a part of object geometry. Using MeshTo CPP will help to export more complex geometry. But I wonder how I could make only that part of geometry not visible during render. Maybe just modyfing faces index or Vertex positons for render time…

you can have as many additional meshes as you like, they won’t appear in the render as long as they are not returned by SimpleObject::GetRenderMesh which would normally be the default simpleobject::mesh. Something like…

void MyObject::UpdateGizmoMesh() 
{
// rebuild the mesh if it's not valid e.g. the pb size has changed 

	if(!(flags & MESH_VALID)) 
	{
		float radius = pblock2->GetFloat(radius);
		float length = pblock2->GetFloat(length);
		float height = pblock2->GetFloat(height);

		BuildMesh(gizmomesh, radius, length, height);
		flags |= MESH_VALID;
	}
}


int MyObject::Display(TimeValue t, INode *inode, ViewExp *vpt, int flags)
{
	SimpleObject::Display(t, inode, vpt, flags);
	if(!pblock2->GetInt(hide_gizmo))
	{
		GraphicsWindow *gw = vpt->getGW();
		Material *mtl = gw->getMaterial();
		Matrix3 mat = inode->GetObjectTM(t);
		gw->setTransform(mat);

// save draw limits

		DWORD rlim = gw->getRndLimits();

// handle the drawing mode

		DWORD rl = GW_WIREFRAME | GW_EDGES_ONLY |/* GW_BACKCULL |*/ (rlim & GW_Z_BUFFER);
		gw->setRndLimits(rl);

// handle selection & frozen

		if (inode->Selected()) 
			gw->setColor( LINE_COLOR, GetSelColor());
		else if(!inode->IsFrozen() && !inode->Dependent())
			gw->setColor( LINE_COLOR, Color(inode->GetWireColor()));

// update & draw

		UpdateGizmoMesh();
		gizmomesh.render( gw, mtl, (flags & USE_DAMAGE_RECT) ? &vpt->GetDammageRect() : NULL, COMP_ALL);

		gw->setRndLimits(rlim);
	}
	return 0;
}

Thanks again, i am gonna try it…

oh, and there are different ways of doing this in newer versions of max but any additional meshes still won’t appear a render just the viewport.

I didn’t get any results but I am reading the SDK Help now, and it says that this method using Display and Graphic Window is deprecated and will only work when legacy display driver are used. As now max uses Nitrous and they suggest to use IObjectDisplay2 interface and PrepareDisplay() method… gonna give it a try…

Dang still nothing… weird…
I followe this help Topic:
http://docs.autodesk.com/3DSMAX/16/ENU/3ds-Max-SDK-Programmer-Guide/index.html?url=files/GUID-94AFDEF6-5BE2-47BC-818D-3BE03DEE0040.htm,topicNumber=d30e36394

I got this code, but nothing displays. I noticed that using my own Mesh variable dont even show geometry in standard way, but using defined by SimpleObject2 mesh variable works.

class AAA_1 : public SimpleObject2
{
[…]
Mesh meshHelper;

virtual BaseInterface* GetInterface(Interface_ID);
virtual unsigned long GetObjectDisplayRequirement() const;
virtual bool PrepareDisplay(const MaxSDK::Graphics::UpdateDisplayContext&);
virtual bool UpdatePerNodeItems(const MaxSDK::Graphics::UpdateDisplayContext&, MaxSDK::Graphics::UpdateNodeContext&, MaxSDK::Graphics::IRenderItemContainer&);
[.....]

};

int AAA_1CreateCallBack::proc(ViewExp *vpt,int msg, int point, int /flags/, IPoint2 m, Matrix3& mat )
{
TimeValue t(0);

if (msg == MOUSE_POINT || msg == MOUSE_MOVE) 
{
	switch(point) 
	{
		case 0: // only happens with MOUSE_POINT msg
			ob->BuildMesh(t);		
			break;

		case 1:
		case 2:
			return CREATE_STOP;
			break;

	}

	ob->NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);

} else if (msg == MOUSE_ABORT) return CREATE_ABORT;

return TRUE;

}

BaseInterface* AAA_1::GetInterface(Interface_ID iid)
{
if (iid == IOBJECT_DISPLAY2_INTERFACE_ID)
{
return (MaxSDK::Graphics::IObjectDisplay2*)this;
}

return __super::GetInterface(iid);

}

unsigned long AAA_1::GetObjectDisplayRequirement() const
{
return 0;
}

bool AAA_1::PrepareDisplay(const MaxSDK::Graphics::UpdateDisplayContext& displayContext)
{
MaxSDK::Graphics::GenerateMeshRenderItemsContext renderItemContext;
renderItemContext.GenerateDefaultContext(displayContext);

MaxSDK::Graphics::IMeshDisplay2* pMeshDisplay = NULL;

pMeshDisplay = static_cast<MaxSDK::Graphics::IMeshDisplay2*>(meshHelper.GetInterface(IMesh_DISPLAY2_INTERFACE_ID));
if (pMeshDisplay != NULL)
	pMeshDisplay->PrepareDisplay(renderItemContext);

return true;

}

bool AAA_1::UpdatePerNodeItems(
const MaxSDK::Graphics::UpdateDisplayContext& displayContext,
MaxSDK::Graphics::UpdateNodeContext& nodeContext,
MaxSDK::Graphics::IRenderItemContainer& targetRenderItemContainer)
{
MaxSDK::Graphics::GenerateMeshRenderItemsContext renderItemContext;
renderItemContext.GenerateDefaultContext(displayContext);
renderItemContext.RemoveInvisibleMeshElementDescriptions(nodeContext.GetRenderNode());

MaxSDK::Graphics::IMeshDisplay2* pMeshDisplay = NULL;

MaxSDK::Graphics::RenderItemHandleArray renderItems;

pMeshDisplay = static_cast<MaxSDK::Graphics::IMeshDisplay2*>(meshHelper.GetInterface(IMesh_DISPLAY2_INTERFACE_ID));

if (pMeshDisplay != NULL)
{
	pMeshDisplay->GetRenderItems(renderItemContext, nodeContext, renderItems);
}

targetRenderItemContainer.ClearAllRenderItems();
targetRenderItemContainer.AddRenderItems(renderItems);
return true;

}

void AAA_1::BuildMesh(TimeValue /t/)
{
ivalid = FOREVER;

meshHelper.setNumVerts(4);
meshHelper.setNumFaces(3);

meshHelper.setVert(0, Point3(0.0, 0.0, 0.0));
meshHelper.setVert(1, Point3(10.0, 0.0, 0.0));
meshHelper.setVert(2, Point3(0.0, 10.0, 0.0));
meshHelper.setVert(3, Point3(0.0, 0.0, 10.0));

meshHelper.faces[0].setVerts(0, 1, 2);
meshHelper.faces[0].setEdgeVisFlags(1, 1, 1);
meshHelper.faces[0].setSmGroup(2);
meshHelper.faces[1].setVerts(3, 1, 0);
meshHelper.faces[1].setEdgeVisFlags(1, 1, 1);
meshHelper.faces[1].setSmGroup(2);
meshHelper.faces[2].setVerts(0, 2, 3);
meshHelper.faces[2].setEdgeVisFlags(1, 1, 1);
meshHelper.faces[2].setSmGroup(4);

meshHelper.InvalidateGeomCache();

}

unsigned long GetObjectDisplayRequirement() const { return MaxSDK::Graphics::ObjectDisplayRequireLegacyDisplayMode; };

You must include that in your Nitrous-supporting class if you want ::Display to be called.

Something weird is happening… I move back once again to GraphicsWindow and Display() method, I found great example that works, but only on Modyfier plugin, looks like this, very similar to Klvnk example:

int myMod::Display(TimeValue t, INode* inode, ViewExp* vpt, int flagst, ModContext* mc)
{
	GraphicsWindow *gw = vpt->getGW();
	DrawLineProc lp(gw);
	lp.SetLineColor(1, 0, 0);
	Point3 my_gismo_points[5] = { Point3(0, 0, 0), Point3(-80, 0, 0),
								  Point3(-60, 10, 0), Point3(-80, 0, 0),
								  Point3(-60, -10, 0) };
	lp.proc(my_gismo_points, 5);
	gw->setColor(TEXT_COLOR, 1, 1, 1);
	gw->text(&my_gismo_points[1], L"Here's the tip of my GIZMO!!!");

	return 0;
}

So ax SDK tells that this is old way and not works and we should Nitrous functions… but this example works great everything is drawn, so I tried the same on my Object plugin and nothing happens…

also I find another example on max SDK showing the same procedure for Object plugin:

    GraphicsWindow* gw = vpt->getGW();
    gw->setTransform(inode->GetObjectTM(t));
    mMesh.render(gw, inode->Mtls(), NULL, COMP_ALL, inode->NumMtls());
    // draw some lines
    gw->polyline(...);

It doesn’t work on my Obecjt projects – I done them by scratch from Plugin Wizard – Nothing works, custom myMesh don’t render, text and lines don’t appear… What am I missing?

Now I am gonna switch again to Nitrous and try ivanisavich solution…

Page 1 / 2