BuildNgonFromPolys() failing...
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 16/03/2006 at 11:56, xxxxxxxx wrote:
Looks like there's one missing detail now...
If I load a .obj file with Ngons using C4D's built-in import, and then set the Structure Browser mode to 'Ngons', I see the list of Ngons/polys, but using my plugin, that list is empty... is there something I need to call to get that list to refresh?
Thanks,
- Keith -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 16/03/2006 at 12:20, xxxxxxxx wrote:
The only reason I can think of is if no ngons are in the object, even though you add them it is possible for the ngon handler to throw them out again if it finds anything invalid (to prevent crashing). After you have finished importing, print out to the console the imported ngon count you should have imported and then what you find in the objects. Does this match? I'll check the BuildNgonFromPolys function to make sure its working, as its unused in CINEMA itself any bugs may have been missed but I should have checked all the functions prior to release (its been a while, can't remember exactly).
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 20/03/2006 at 11:26, xxxxxxxx wrote:
Hey David,
I checked and the Ngons are being created and the Ngon count seems to be correct. In fact, I finished implementing the export side of things and all the calls used for that are retrieving the data correctly as well - but if I set the display Mode to 'N-Gons' in the Structure Browser, it's blank (no polys, no ngons, no nothing is listed).
This is the code that I finally got working://======== S N I P - bunch-o-code above here to set up the object if( m_opt_mpNgons && m_numNgons ) // see if we need to set up Ngons... { op->GetNgon(); // force NgonBase to be created pNgonBase = op->GetNgonBase(); if( pNgonBase ) { op->Message(MSG_UPDATE); NgonLoader *pNgons = &m_pNgons[0]; // <-- NgonLoader is my own structure for(i=0; i<m_numNgons; i++) { LONG ndx; LONG *pEdge = &m_pEdgeList[0]; // <-- array big enough to hold max-ngon-edges if( m_opt_mpRevFaces ) { for(ndx=0; ndx<pNgons->polycnt; ndx++) // default action is to reverse faces, so this logic is backwards... { if( ndx == 0 ) // if this is the first poly, add edge #0 *pEdge++ = (pNgons->polys[ndx] * 4)+0; *pEdge++ = (pNgons->polys[ndx] * 4)+1; // add edge #1 if( ndx == pNgons->polycnt-1 ) // if this is the last poly, add edge #3 *pEdge++ = (pNgons->polys[ndx] * 4)+3; } } else { for(ndx=pNgons->polycnt-1; ndx>=0; ndx--) // need to reverse order for proper winding { if( ndx == pNgons->polycnt-1 ) // if this is the first poly, add edge #3 *pEdge++ = (pNgons->polys[ndx] * 4)+3; *pEdge++ = (pNgons->polys[ndx] * 4)+0; // add edge #0 if( ndx == 0 ) // if this is the last poly, add edge #1 *pEdge++ = (pNgons->polys[ndx] * 4)+1; } } pNgonBase->BuildNgon(NULL, m_pEdgeList, 0, pNgons->polycnt+2, vadr, padr); pNgons++; } pNgonBase->InitMap(); pNgonBase->SetFlags(NGON_FLAG_NOVALIDATION); } } doc->InsertObject(op,NULL,NULL); op->MakeTag(Tphong); op->Message(MSG_UPDATE); doc->SetActiveObject(op); }
...in the above code, the 'NgonLoader ' is my own structure, that keeps track of the triangles (no quads, in this case) that make up the Ngons. Also, by default, I reverse the winding order of polygons on import, to fit C4D's system (there's an option that lets you 'reverse faces', which in this case actually loads them as they are found in the file). Anyway, the above code checks for each condition and sets up the Ngon edges appropriately for each case.
So, as I mentioned, the code 'appears' to be working correctly - it creates Ngons, which are visible/selectable/etc. in the editor window, if I enable the option to view Ngons, I can see the original triangles that make up the Ngons and op->GetNgonCount(), op->GetPolygonTranslationMap(), op->GetNGonTranslationMap(), op->GetNgon() and op->GetNgonEdgesCompact() all seem to be working correctly. The only thing that seems to not be working is the Structure Manager display, as described above.
Any thoughts?
Thanks,
- Keith -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 20/03/2006 at 11:46, xxxxxxxx wrote:
BTW, I just thought I'd comment on something for future reference...
"The Ngon System sucks" :).
...I feel better now :). Seriously though, it could be that I missed something, but I noticed that it's just really really tedius trying to figure out a list of points that make up any particular Ngon. I mean.. you can:
ngonCnt = op->GetNgonCount(); // <-- usefull information
Pgons = op->GetNgon(); // <-- more useful data
Pgons[i].GetPointCount(); // <-- cool, we know how many points but...
Pgons[i].GimmeDaDamnPoints(&mybuffer); // <-- ...where's this helper function???
...instead, you have to jump through a bunch of hoops looping through edges (and making sure to get the rght order of edges, at that), then extract the points used by those edges.
As I mentioned, it's possible that I just missed something, or went about it entirely the wrong way, but having not written the code to start with (ie. from an outside perspective), it's just really non-obvious. My exporting code seems to be functioning fine now, I'm just not completely comfortable that it will continue to work without changes in future versions of C4D.
Just some food for thought...
Thanks,
- Keith -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 21/03/2006 at 00:42, xxxxxxxx wrote:
Sorry no idea why the structure manager isn't working. The best bet would be to send an example file with your compiled plugin to the sdk support mail and I'll take a look for you.
As for the ngon library, as I mentioned before the intention is to use the modeling library and not directly using the ngons since this is more work and the library essentially is just giving you raw access with a few helpers. Its not really advisable to use the ngons directly since this is a delicate area and can easily cause crash problems if the data is wrongly setup. The modeling library is easier and safer. -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 21/03/2006 at 05:22, xxxxxxxx wrote:
Ok, I'll try to send something for you to look at once I get to a breaking point - thanks.
As for the ngon library, I'm not opposed to using that, or married to an particular set of calls - I'm just trying to figure out 'how' to do what I need to do. For Riptide, I need to do 2 things, related to ngons...
1. For Import: read an .obj file, which might include ngons and if so, set those up in the resulting C4D PolygonObject, without changing the vertex ordering.
2. For Export: parse a C4D PolygonObject to determine if it has any ngons and if so, determine which polygons make up the ngons (so I don't write those out as tris/quads) and then determine the actual ngon point indices that make up the ngons, so I can build proper .obj file format facet records for the ngons.
...my import code is shown above and is just using pNgonBase->BuildNgon() (which I guess qualifies as "ngon library" ?). The export code is a bit more involved, because I was trying to find some way of getting the information I needed. Here's the basic code I'm using for exporting:// here's a few of my internal support structures... typedef struct _objFacet // facet (or 'face') structure { DWORD fctFlags; DWORD iMatNdx; // material ID/index DWORD iGroupNdx; // group ID/index DWORD iRegionNdx; // UVMapper region index DWORD iPolyNdx; // vertex indices DWORD iNgonNdx; // which Ngon this face is part of (if any) DWORD v[4]; DWORD t[4]; DWORD n[4]; DWORD vCount; // num vertices in this face } objFacet; typedef struct _ngonsavedata { Bool bWritten; DWORD iMatNdx; // material ID/index DWORD iGroupNdx; // group ID/index DWORD iRegionNdx; // UVMapper region index DWORD *v; DWORD *t; DWORD *n; DWORD vCount; // num vertices in this ngon } NgonData; void ObjSaver::GetNgonsData(PolygonObject *op) { NgonData *pNgonData; Pgon *pPgon; LONG ngoncnt, *polymap, **ngons; LONG i, j, numpolys, numpoints, loopBreak, ptCnt, firstPt, nextPt; UCHAR *edges; m_numNgons = op-> **GetNgonCount** (); if( !m_numNgons ) return; m_pNgonsData = (NgonData * )GeAlloc(m_numNgons * sizeof(NgonData)); if( !m_pNgonsData ) { m_numNgons = 0; return; } if( !op-> **GetPolygonTranslationMap** (ngoncnt, polymap) ) { GeFree(m_pNgonsData); m_pNgonsData = NULL; m_numNgons = 0; return; } if( !op-> **GetNGonTranslationMap** (ngoncnt, polymap, ngons) ) { GeFree(m_pNgonsData); GeFree(polymap); m_pNgonsData = NULL; m_numNgons = 0; return; } pPgon = op-> **GetNgon** (); op-> **GetNgonEdgesCompact** ( **edges** ); pNgonData = &m_pNgonsData[0]; for(i=0; i<(LONG)m_numNgons; i++) { numpolys = ngons[i][0]; numpoints = pPgon[i]. **GetPointCount** (); pNgonData->v = (DWORD * )GeAlloc(numpoints * sizeof(DWORD)); pNgonData->t = (DWORD * )GeAlloc(numpoints * sizeof(DWORD)); pNgonData->n = (DWORD * )GeAlloc(numpoints * sizeof(DWORD)); pNgonData->bWritten = false; ptCnt = 0; j = 1; // the index list starts at ngons[i][1] loopBreak = 0; firstPt = NOTOK; nextPt = NOTOK; //=========================================================================================== // The hoop-jumping below is tedius... I wish I could replace it all with a single helper // function call -> pPgon[i].GetPoints() //=========================================================================================== while(loopBreak < numpoints) // allow for complete poly scan per point { LONG polyndx; objFacet *pFacet; polyndx = ngons[i][j]; // get the polygon index pFacet = &m_pFaces[polyndx]; // get ptr to this facet pFacet->fctFlags |= FCTF_ISNGON; // flag it as an Ngon pFacet->iNgonNdx = i; // and store the Ngon index for later //======================================================================================= // The basic strategy is to look at each 'active' edge, extracting the points that make // up the outer edge of the Ngon. Since the order of those edges is not necessarily // correct, keep track of 'which' edge we're looking for next (the next correct edge will // have it's first point == the second point of the previous edge). // // Since the edge list is out of order, we might have to pass up some edges and scan // through the list from the top again for any particular point we're looking for, so // the loop-control is set up to allow for one list-scan per point. // // In hindsight, I guess I could have just stored all the edges and implemented a 'sort' // on them (based on the critera above), but that didn't occur to me when I wrote this code :). // // Also note that some polygons that make up the Ngon may not have any edges that make // up the (outer) edge of the Ngon. //======================================================================================= if( !( **edges** [polyndx] & (1 << 0)) ) // edge 0 { if( firstPt == NOTOK ) { firstPt = m_pPolys[polyndx].a; pNgonData->v[ptCnt] = m_pPolys[polyndx].a; if( m_pUVndx ) pNgonData->t[ptCnt] = m_pUVndx[polyndx].a; if( m_pNormNdx ) pNgonData->n[ptCnt] = m_pNormNdx[polyndx].a; ptCnt++; nextPt = m_pPolys[polyndx].b; } else if( m_pPolys[polyndx].a == nextPt ) { pNgonData->v[ptCnt] = m_pPolys[polyndx].a; if( m_pUVndx ) pNgonData->t[ptCnt] = m_pUVndx[polyndx].a; if( m_pNormNdx ) pNgonData->n[ptCnt] = m_pNormNdx[polyndx].a; ptCnt++; nextPt = m_pPolys[polyndx].b; } if( ptCnt == numpoints ) break; } if( !( **edges** [polyndx] & (1 << 1)) ) // edge 1 { if( firstPt == NOTOK ) { firstPt = m_pPolys[polyndx].b; pNgonData->v[ptCnt] = m_pPolys[polyndx].b; if( m_pUVndx ) pNgonData->t[ptCnt] = m_pUVndx[polyndx].b; if( m_pNormNdx ) pNgonData->n[ptCnt] = m_pNormNdx[polyndx].b; ptCnt++; nextPt = m_pPolys[polyndx].c; } else if( m_pPolys[polyndx].b == nextPt ) { pNgonData->v[ptCnt] = m_pPolys[polyndx].b; if( m_pUVndx ) pNgonData->t[ptCnt] = m_pUVndx[polyndx].b; if( m_pNormNdx ) pNgonData->n[ptCnt] = m_pNormNdx[polyndx].b; ptCnt++; nextPt = m_pPolys[polyndx].c; } if( ptCnt == numpoints ) break; } if( pFacet->vCount == 4 ) // only process edge 2 if this is a quad { if( !( **edges** [polyndx] & (1 << 2)) ) // edge 2 { if( firstPt == NOTOK ) { firstPt = m_pPolys[polyndx].c; pNgonData->v[ptCnt] = m_pPolys[polyndx].c; if( m_pUVndx ) pNgonData->t[ptCnt] = m_pUVndx[polyndx].c; if( m_pNormNdx ) pNgonData->n[ptCnt] = m_pNormNdx[polyndx].c; ptCnt++; nextPt = m_pPolys[polyndx].d; } else if( m_pPolys[polyndx].c == nextPt ) { pNgonData->v[ptCnt] = m_pPolys[polyndx].c; if( m_pUVndx ) pNgonData->t[ptCnt] = m_pUVndx[polyndx].c; if( m_pNormNdx ) pNgonData->n[ptCnt] = m_pNormNdx[polyndx].c; ptCnt++; nextPt = m_pPolys[polyndx].d; } if( ptCnt == numpoints ) break; } } if( !( **edges** [polyndx] & (1 << 3)) ) // edge 3 { if( firstPt == NOTOK ) { firstPt = m_pPolys[polyndx].d; pNgonData->v[ptCnt] = m_pPolys[polyndx].d; if( m_pUVndx ) pNgonData->t[ptCnt] = m_pUVndx[polyndx].d; if( m_pNormNdx ) pNgonData->n[ptCnt] = m_pNormNdx[polyndx].d; ptCnt++; nextPt = m_pPolys[polyndx].a; } else if( m_pPolys[polyndx].d == nextPt ) { pNgonData->v[ptCnt] = m_pPolys[polyndx].d; if( m_pUVndx ) pNgonData->t[ptCnt] = m_pUVndx[polyndx].d; if( m_pNormNdx ) pNgonData->n[ptCnt] = m_pNormNdx[polyndx].d; ptCnt++; nextPt = m_pPolys[polyndx].a; } if( ptCnt == numpoints ) break; } // funky loop control... if( j == numpolys ) { j = 1; loopBreak++; } else { j++; } } pNgonData->vCount = ptCnt; pNgonData++; } GeFree(polymap); GeFree(ngons); }
...as I mentioned, this code seems to be working fine, but I'm just not crazy about the method of going about it. I could have replacd that entire lower loop if there was a helper Pgon->GetPoints(&my_buffer) call available.
Anyway, I've highlighted the relevent calls and structures being used above and I'm guessing that my use of those is relatively benign and should continue to work, as long as the documented functionality of those calls don't change in future versions.
- Keith -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 21/03/2006 at 14:14, xxxxxxxx wrote:
David, could you (or anyone who knows) give me the SDK Support e-mail address? I couldn't find it listed anywhere, but apparently it's not: [email protected]
Thanks,
- Keith
*** Ok, I did a forum search and it looks like it might be [email protected] so I sent it there. If you don't get my e-mail let me know. -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 21/03/2006 at 14:33, xxxxxxxx wrote:
Got it, thanks (yes its sdk_support).
I tested the import on 9.5 and it works fine, ngons are fine and the structure manager shows them correctly. What version of CINEMA are you using? Your original post says 9.1, is that correct? I don't have 9.1 on my laptop at the moment to check so if you are using 9.1 I'll check it on my desktop tomorrow. -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 21/03/2006 at 18:42, xxxxxxxx wrote:
Cool... yes, I am using 9.1 and seeing the same thing on both Mac and PC R9.1 on both.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 22/03/2006 at 01:29, xxxxxxxx wrote:
Strange. Tested 9.1 this morning with no problems either. What happens if you run the retriangulate ngons function or the remove ngons function, does the structure manager then work?
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 22/03/2006 at 02:34, xxxxxxxx wrote:
Hmmm... I just tried retriangulate ngons and that fixes the SM display list, but on that sample file I sent you now the top and bottom (both ngons) are missing one triangle (the last triangle created in each case.. where the sequence of points connects back to the start point.
Remove ngons also fixes the SM display.
Just for reference, my C4D version is V9.102 -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 22/03/2006 at 02:44, xxxxxxxx wrote:
...apparently selecting an ngon and doing a 'reverse normals' also does a retriangulate... giving the same results as above - it loses a triangle.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 22/03/2006 at 03:37, xxxxxxxx wrote:
Anything that causes the ngon to be retriangulated will give it the optimal mesh, which can include quads. I'm at a loss why your SM isn't working, given it works fine here under 9.1 and 9.5 I'm afraid I have no way to help you find out why yours does not work. For the SM to not work would suggest a problem with the ngons, also given that retriangulate then makes it work that too suggests a ngon data problem yet it works ok here, very odd
All I can suggest is to try a clean install of CINEMA to ensure nothing else is causing it, but I can't think what would. -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 22/03/2006 at 04:14, xxxxxxxx wrote:
Strange... any thoughts on retriangulate causing a missing triangle? Are you seeing that too, or not? (I'm just wondering if it's the same/related issue that's only showing up on my system).
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 22/03/2006 at 04:45, xxxxxxxx wrote:
Ah sorry, my mistake actually. I'd been just loading and thought the obj import would use your own, but it doesn't I noticed the plugin menu entry, on trying it with that yes I do get the missing SM data.
I looked through the ngon edge data, there is a missing ENDSEGMENT marker, on looking at your import code again I also couldn't see one there. In the docs it mentions PGONEDGE_ENDSEGMENT but doesn't clarify why or when you need to use it. This marks the end of an ngon segment, with BuildNgon you could have multiple segments (holes). On the last edge for each segment you need to mark it. I forced the marker bit during BuildNgon and it then works fine, so you just need to add that to your code and all should be working now.
I'll ask that the docs make this clearer and that we add some more helpers so you don't need to deal with such raw data in/out of the ngons without needing to go to the modeling library which isn't always suitable for non-modeling cases like this. -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 22/03/2006 at 06:02, xxxxxxxx wrote:
Ah! Great - thanks. Now I just need to figure out how (and where) to set that bit... :).
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 22/03/2006 at 06:38, xxxxxxxx wrote:
On the last edge in the array, just do |PGONEDGE_ENDSEGMENT. That is assuming you aren't adding any holes, otherwise it would be the last edge for each segment (the main outline, then each hole).
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 23/03/2006 at 04:31, xxxxxxxx wrote:
Got it... and that fixed the problem - thanks!
Just to recap a bit...
On the BuildNgonFromPolys() issue, since you have to pass the edge list to it afterall (not optional, as the docs say) then that function doesn't really seem to provide anything useful over BuildNgon()... I'd just get rid of it if noone's using it (maybe just remove it from the docs).
And yes, in my case, I'm not really modelling (on export, at least), so having some easy way to just get an ordered list of points of an Ngon would make writing things like export plugins a lot easier.
After looking around some more, it looks like I could have maybe used the modelling library pNgonBase- >GetNgon() and had a list of points in the Ngon class (instead of working with the Pgon class from the PolygonObject's op- >GetNgon()), but it's not clear from the docs whether that list of points is in the right order (?) so I might still have had to walk the segment list (?).
Anyway, I think everything is working now, so thanks a lot for all the help!
- Keith -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 09/04/2008 at 11:12, xxxxxxxx wrote:
I'm in the process of a massive revamp of all the code listed previously in this thread, but I just wanted to add a comment for future reference...
While not specifically documented as such, pNgonBase- >BuildNgon() requires that in addition to the PGONEDGE_ENDSEGMENT flag for end segments, you also have to set the PGONEDGE_NOEDGES flag for any polys included in the Ngon, but have no outer (or potentially inner) edges that make up the edge list.
In my case, it seems to be sufficient to just add one edge (I use the 0 edge) to the list for each of those polys, like so...
pEdges[edgecount++] = (noedge_poly_index * 4)+0 | PGONEDGE_NOEDGES;
...I am adding that (or those) to the 'outer' edge list that I'm passing to **pNgonBase- >BuildNgon() **and this seems to have fixed some cases where a poly contributed no outer edges (I'm not passing the inner edge list, since I'm not doing 'holes'). -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 09/04/2008 at 11:17, xxxxxxxx wrote:
(I realize the '+0' is unneeded and not doing anything, it's just there to indicate the 0 edge ).