Drawing large amounts of billboarded triangles in the viewport



  • @r_gigante Hey thanks for the great suggestions.
    Not sure why I didn't think of adding a camera check... Now in combination with the BaseDraw::DrawPolygonObject() the performance is quite ok.
    If I could bother you guys for 1 more question : ), would really appreciate it. It is regarding per vertex colors. I followed the guide here - https://developers.maxon.net/docs/Cinema4DCPPSDK/html/page_manual_vertexcolortag.html
    Created the VertexColorTag , inserted in the PolygonObject, got the write address and filled it up, but i'm crashing at VertexColorTag::Get() during the write process.
    Is there anything specific when using the per vertex color tag in a PolygonObject that is drawn with BaseDraw::DrawPolygonObject(). Basically should that guide work out of the box?

    Regards,
    Georgi.



  • Hi @mastergog the manual just illustrates the standard case and, as much as for any other snippet, it might be adapted to your scope to deliver the desired function.

    Give the limited information, I can only assume that the VertexColorHandle passed as first parameter to VertexColorTag::Get() might be invalid. Have you checked if vcTag->GetDataAddressW(); returns a valid pointer? Can you share a code to reproduce the issue? What's the instance scope in the code of the PolygonObject you've inserted to Tag into?

    Cheers, r



  • @maxon Hey sorry for the weird phrasing, had some other tasks and I was just wondering if there is some known issue with this functionality before i got back to it.

    Anyway about the code. As suggested, created a zero polygon PolygonObject* with my base vertices in GetVirtualObjects() and inserted it under the cache root.
    In Draw() I find that PolygonObject and use its point data to allocate a PolygonObject with actual polygons that is drawn with DrawPolygonObject(). This just created PolygonObject pointer is kept as a member in my class.

    So the vertex color tag code is the following. And the VertexColorHandle seems to be valid. Tried this code in both my Draw() and GetVirtualObjects() implementation to the same effect.

                    BaseTag* tag = polygonObjectToDraw->GetTag(Tvertexcolor);
    		if (tag == nullptr) {
    			tag = VertexColorTag::Alloc(polygonObjectToDraw->GetPointCount());
    			VertexColorTag* vcTag = static_cast<VertexColorTag*>(tag);
    			vcTag->SetPerPointMode(false);
    		}
    
    		VertexColorTag* vcTag = static_cast<VertexColorTag*>(tag);
    		VertexColorHandle handle = vcTag->GetDataAddressW();
    		for (Int32 i = 0; i < Int32(polygonObjectToDraw->GetPointCount()); i++)
    		{
    			VertexColorStruct vcs;
    			VertexColorTag::Get(handle, i, vcs);
    
    			for (int p = 0; p < 4; p
    				++)
    			{
    				vcs[p] = maxon::ColorA32(1.0f, 1.0f, 0.0f, 1.0f);
    			}
    			VertexColorTag::Set(handle, i, vcs);
    		}
    
    		polygonObjectToDraw->InsertTag(tag);
    
    		baseDraw->DrawPolygonObject(baseDrawHelp, polygonObjectToDraw, DRAWOBJECT::NONE);
    
    


  • @maxon Hey so the crashing was because I was looping out of bounds it seems. Corrected my code like so:

                   BaseTag* tag = polygonObjectToDraw->GetTag(Tvertexcolor);
    		if (tag == nullptr) {
    			tag = VertexColorTag::Alloc(polygonObjectToDraw->GetPolygonCount() * 4);
    			VertexColorTag* vcTag = static_cast<VertexColorTag*>(tag);
    			vcTag->SetPerPointMode(true);
    		}
    
    		VertexColorTag* vcTag = static_cast<VertexColorTag*>(tag);
    		VertexColorHandle handle = vcTag->GetDataAddressW();
    		for (Int32 i = 0; i < Int32(polygonObjectToDraw->GetPolygonCount()); i++)
    		{
    			VertexColorStruct vcs;
    			VertexColorTag::Get(handle, i, vcs);
    
    			for (int p = 0; p < 4; p++)
    			{
    				vcs[p] = maxon::ColorA32(1.0f, 1.0f, 0.0f, 1.0f);
    			}
    			VertexColorTag::Set(handle, i, vcs);
    		}
    
    		polygonObjectToDraw->InsertTag(tag);
    
    		baseDraw->DrawPolygonObject(baseDrawHelp, polygonObjectToDraw, DRAWOBJECT::NONE);
    

    Still this doesn't use the color i've specified, but rather the default grey.



  • @maxon Hey guys, one more update.
    Edited my code so that I allocate the full PolygonObject in GetVirtualObjects(), place it under the cache, and just modify it in Draw(), without using DrawPolygonObject()
    Managed to get the per vertex colors to show when I select my object, click "c" so i can get the edit mode and see the cache. Then I select the PolygonObject in the cache with the per vertex color tag and double click the tag as if I'm editing the colors. That's when my colors show up.

    Any ideas how to get them without going into edit mode and double clicking the tag?

    Regards,
    Georgi.



  • @maxon @r_gigante

    Hey guys, it was suggested to me that the vertex color tag is designed to pass data to the renderer not the viewport. And the reason my colors were showing up using the paint tool was because it overrides the viewport. Is that correct?

    Also one of your tutorials showed how to create a Material with a vertex map using a vertex color tag, so I tried that. And applied the Material to my object and the colors showed up. So perhaps this is the "correct" way to use the vertex color tag for representation in the viewport? Achieved this through the UI but I assume there's a way to do it programmatically. correct?

    Thanks for taking the time!

    -Georgi.



  • Ok resolved this by making the following connection TextureTag->Material->Shader->VertexColorTag and inserting the TextureTag in my object.

    Going to close this. Thanks for the support.



  • Hi @mastergog,

    we are sorry that it took us so long. We actually were aware of your problem, and had it in the workings, but were a bit busy with all the new Apple stuff and Cinema supporting it from the get go. Thank your for sharing your solution and thank you for your understanding.

    Cheers
    Ferdinand



  • @zipit Oh no worries you provided great support to get me started. As someone had suggested will also write you guys a more detailed email about the next representations I plan on implementing.

    Regards,
    Georgi.



  • As already told by @zipit, I'm terribly sorry for coming so late here.
    I've prepared a full example showing how to fill a VertexColorTag in the ObjectData::GetVirtualObjects() and use this values to color the triangles shown up in the ObjectData::Draw() method. My code actually uses the VertexColorTag::SetColor()/GetColor().
    5b4213d8-e4b4-434a-ad71-5ef0d69be6ea-image.png

    The VertexColorTag in this case is not specify to each vertex of the triangle but specifies the color for the whole triangle: this is because the tag is created in the ObjectData::GetVirtualObjects() and store color for each point of the cloud, but then it's used in the ObjectData::Draw() method to specify the ObjectColorProperty used to color the drawn PolygonObject. As far as I know the BaseDraw::DrawPolygonObject() ignores any VertexColorTag assigned to the PolygonObject to be drawn.

    BaseObject* PC_12974::GetVirtualObjects(BaseObject* op, HierarchyHelp* hh)
    {
    	// check cache before continue
    	BaseObject* cache = op->GetCache();
    	if (cache)
    		return cache;
    	
    	// init the random gen and get a arbitrary number of tris
    	_rndGen.Init(GeGetTimer());
    	_randomTrisCnt = (SAFEINT32(_rndGen.Get01() * (1 + _max - _min)) + _min);
    	
    	
    	// allocate a PolygonObject and fill it with points randomly
    	PolygonObject* po = PolygonObject::Alloc(_randomTrisCnt, 0);
    	if (!po)
    		return BaseObject::Alloc(Onull);
    	
    	// fill the points array with random positions
    	Vector* points = po->GetPointW();
    	for (Int32 i = 0; i < _randomTrisCnt; i++)
    		points[i] = Vector (100.0 * _rndGen.Get11(), 100.0 * _rndGen.Get11(), 100.0 * _rndGen.Get11());
    
    	// look for VertexColor tag
    	BaseTag* tag = po->GetTag(Tvertexcolor);
    
    	// if not existing just create a new one
    	VertexColorTag* vcTag = nullptr;
    	if (!tag)
    	{
    		tag = VertexColorTag::Alloc(_randomTrisCnt);
    		po->InsertTag(tag);
    	}
    
    	vcTag = static_cast<VertexColorTag*>(tag);
    	vcTag->SetPerPointMode(true);
    	VertexColorHandle handle = vcTag->GetDataAddressW();
    	
    	// fill the vertexcolor tag with random values
    	for (Int32 i = 0; handle && i < _randomTrisCnt; i++)
    		VertexColorTag::SetColor(handle, nullptr, nullptr, i, maxon::Color32(_rndGen.Get01(), _rndGen.Get01(), _rndGen.Get01()));
    
    	// update host object
    	po->Message(MSG_UPDATE);
    	
    	return po;
    	
    }
    
    Bool PC_12974::TriangleOnPoint(const Vector &pos, PolygonObject& po)
    {
    	// given a point create a triangle centered over there.
    	Vector* points = po.GetPointW();
    	const Matrix poMG = po.GetMg();
    	const Vector posMG = poMG * pos;
    	if (!points)
    		return false;
    	
    	// set vertexes positions for the triangle.
    	points[0] = Vector(0,  0, _triangleRad) + posMG;
    	points[1] = Vector(_triangleRad * Cos(-PI / 6), 0, _triangleRad * Sin(-PI / 6)) + posMG;
    	points[2] = Vector(_triangleRad * Cos(-PI * 5 / 6), 0, _triangleRad * Sin(-PI * 5 / 6)) + posMG;
    	
    	// create the polygon
    	CPolygon* polys = po.GetPolygonW();
    	if (!polys)
    		return false;
    	
    	polys[0] = CPolygon(0, 1, 2);
    	
    	return true;
    }
    
    DRAWRESULT 	PC_12974::Draw (BaseObject *op, DRAWPASS drawpass, BaseDraw *bd, BaseDrawHelp *bh)
    {
    	// skip anything but OBJECT drawpass
    	if (drawpass != DRAWPASS::OBJECT)
    		return DRAWRESULT::SKIP;
    
    	// check for the object and its cache
    	if (op && op->GetCache())
    	{
    		// get the PolygonObject from the cache
    		PolygonObject* opPO = static_cast<PolygonObject*>(op->GetCache());
    		
    		// look for the attached VertexColor Tag
    		BaseTag* const tag = opPO->GetTag(Tvertexcolor);
    		if (!tag)
    			return DRAWRESULT::SKIP;
    		VertexColorTag* const vcTag = static_cast<VertexColorTag*>(tag);
    		
    		// retrieve the read-only handle
    		ConstVertexColorHandle vcTagHandleR = vcTag->GetDataAddressR();
    		
    		// get the points and iterate over the VertexColor to set the color
    		// of each triangle drawn
    		maxon::Int pointCnt = opPO->GetPointCount();
    		Vector const *points = opPO->GetPointR();
    		for (maxon::Int i = 0; i < pointCnt; i++)
    		{
    			
    			maxon::Color32 vtxCol(0.0);
    			
    			// get the color
    			if (vcTagHandleR && vcTag->IsPerPointColor())
    			  vtxCol = VertexColorTag::GetColor(vcTagHandleR, nullptr, nullptr, (Int32)i);
    
    			// set the color in the ObjectColorProperties
    			ObjectColorProperties colProp;
    			colProp.usecolor = ID_BASEOBJECT_USECOLOR_ALWAYS;
    			colProp.color.x = vtxCol.r;
    			colProp.color.y = vtxCol.g;
    			colProp.color.z = vtxCol.b;
    			colProp.xray = false;
    			
    			// allocate the temp triangle
    			PolygonObject* tri = PolygonObject::Alloc(3, 1);
    			
    			// set the color prop, create the tri and draw!
    			tri->SetColorProperties(&colProp);
    			if (TriangleOnPoint(op->GetMg() * points[i], *tri))
    				bd->DrawPolygonObject(bh, tri, DRAWOBJECT::NONE, nullptr);
    
    			// free the tri
    			PolygonObject::Free(tri);
    			
    		}
    
    	}
    	
    	return DRAWRESULT::OK;
    
    }
    
    

    Feel free to comment and again sorry for the silence.

    Riccardo