Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Drawing large amounts of billboarded triangles in the viewport

    Cinema 4D SDK
    c++ r23 sdk
    4
    16
    2.3k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • M
      mastergog @r_gigante
      last edited by

      @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/cpp/2023_2/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.

      maxonM 1 Reply Last reply Reply Quote 0
      • maxonM
        maxon @mastergog
        last edited by maxon

        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

        M 1 Reply Last reply Reply Quote 0
        • M
          mastergog @maxon
          last edited by

          @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);
          
          
          1 Reply Last reply Reply Quote 0
          • M
            mastergog
            last edited by mastergog

            @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.

            1 Reply Last reply Reply Quote 0
            • M
              mastergog
              last edited by

              @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.

              1 Reply Last reply Reply Quote 0
              • M
                mastergog
                last edited by mastergog

                @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.

                1 Reply Last reply Reply Quote 0
                • M
                  mastergog
                  last edited by

                  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.

                  1 Reply Last reply Reply Quote 0
                  • ferdinandF
                    ferdinand
                    last edited by

                    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

                    and Cinema supporting it from the get go. Thank your for sharing your solution and thank you for your understanding.

                    Cheers
                    Ferdinand

                    MAXON SDK Specialist
                    developers.maxon.net

                    M 1 Reply Last reply Reply Quote 0
                    • M
                      mastergog @ferdinand
                      last edited by

                      @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.

                      1 Reply Last reply Reply Quote 0
                      • r_giganteR
                        r_gigante
                        last edited by

                        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

                        1 Reply Last reply Reply Quote 0
                        • First post
                          Last post