BuildNgonFromPolys() failing...
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 13/03/2006 at 08:38, xxxxxxxx wrote:
"Another issue i just remembered is the ordering of ngon polys. I think they must be at the end of the polygon array, and arranged in blocks that make up the ngons. Like this:
p1 ... pa| pa+1 ... pb| pb+1 ... pc| ... quads/tris | ngon1 | ngon2 | ...
"
...hmm, are you saying that I need to add duplicates of the polygons that make up the Ngons to the end of the polygon list? I assumed that BuildNgonFromPolys() would handle that. If I do need to duplicate the polys myself, I'm not clear on what the ResizeObject() call should be... higher polycount + higher Ngon count?
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 13/03/2006 at 09:16, xxxxxxxx wrote:
I don't know if polys are dublicated.. i would say no, but it is possible.. I guess you are right that BuildNgonFromPolys() should handle this, or any reordering that might be nessesary.
I would write that test plugin above, just in the same way you did, so i really don't know what is wrong.
Perhaps you could look at an existing objects with ngons to see how the polys are ordered ( GetPolygonTranslationMap() )
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 15/03/2006 at 07:18, xxxxxxxx wrote:
Thanks Michael.
Just to clarify - still no joy on this. If someone from Maxon could look at my plugin above and explain why it's not working, I'd appreciate it.
Thanks,
- Keith -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 15/03/2006 at 08:04, xxxxxxxx wrote:
BuildNgonFromPolys needs the ngon outline passing in 'outer', the docs incorrectly state this is optional.
To build an ngon, you can use the Modeling class and CreateNgon in which case it will create the ngon itself (the outline defining it) and the internal polygons that form the ngon. If you already have the polygons then you can use either the BuildNgon of BuildNgonFromPolys in which case you have the ngon already triangulated as polygons and just want to add the ngon outline.
I took a quick look over your posted code, you don't need the ResizeObject and if you are not changing a value in ResizeObject then just pass NOTOK. -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 15/03/2006 at 10:34, xxxxxxxx wrote:
Great - Thanks!
So, BuildNgonFromPolys() takes care of resizing the object - cool. I guess that leads me to my next question :)... if I need to pass the outer array, could you explain how that is built? in other words, how are the edge indices computed? per polygon passed in? based on the set I pass in? based on the entire list of polygons in the object? Is there some sort of 'GetEdges()' helper function for a PolygonObject?
I'll look through the docs again, but I don;t recall seeing anything on that subject (at least, related to BuildNgonFromPolys()).
Thanks again,
- Keith -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 15/03/2006 at 10:50, xxxxxxxx wrote:
...actually, I'm not even clear on what the 'outer' array IS :). Here's the SDK docs:
LONG* outer
> An optional array of the outline of the N-gon. You can use the internal mark (PGONEDGE_ENDSEGMENT) to mark segments in the N-gon outline. The caller owns the pointed array.
>
> ...so is outer an array of polygon indices? an array of edge indices (and if so, where/how are they computed)? something else?
>
> Thanks.
>
> -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 15/03/2006 at 13:44, xxxxxxxx wrote:
The SDK doc is actually incorrect for the outer, unlike the BuildNgon function the BuildNgonFromPolys can not support holes so the 'outer' is simply an array of the ngon outer edges.
If you need to use holes then BuildNgon must be used. Normally this function is used because you already know the ngon outline and have triangulated the ngon yourself so wish to pass the ngons outer edges and also the polygons for the triangulation (e.g. during file import).
If you don't already know the ngon outline then you will need to find this based on whatever you do know, is that just a list of connected polygons? The Neighbor class might help if you just know the vertices or polygons. -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 16/03/2006 at 02:13, xxxxxxxx wrote:
Ahh, thanks again David... but related to the above:
1. I don't need to create holes.
2. I know exactly which polygon indices will make up the Ngon and those polys are already created.
3. I know exactly which vertex (point) indices are used to make up the outer edge of the polygon.
...the issue that's still not clear to me is:
>> ...so the 'outer' is simply an array of the ngon outer edges.
...sorry if I'm being dense, but I guess I still hadn't found a way to know what 'index' any particular edge a->b of a particular polygon IS. It sounds like every edge found within the PolygonObject has a unique/numbered index and that that index value is what the array is made up from, but I don't know how to GET that index value for the edges in question.
If it was simply an array of the POINT indices that make up the Ngon, that would be simple - I have those readily available. But to get the edge indices, the round-about way I see so far would be to:
- initialize a Neighbor object with the PolygonObject info
- for each triangle that will make up the Ngon, call polyinfo = neighbor->GetPolyInfo()
- In my particular case, the first two (outer) edges of each triangle are the ones I need an index for, so I get those two PolygonObject-relative 'edge index' values from polyinfo->edge[0] and polyinfo->edge[1] (???)
...is that right? Is that the uniquely numbered edge indices I need for the array passed to BuildNgonFromPolys() ? (from some initial tests, that doesn't seem to work).
- Keith -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 16/03/2006 at 02:17, xxxxxxxx wrote:
...also, if I don't call ResizeObject(), then my call to GetNgonBase() fails (at least if the object has ot yet been attached to the document... I can go ahead and add it to the document first, but I'm still fuzzy on building the edge-index array).
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 16/03/2006 at 02:44, xxxxxxxx wrote:
- In my particular case, the first two (outer) edges of each triangle are the ones I need an index for, so I get those two PolygonObject-relative 'edge index' values from polyinfo->edge[0] and polyinfo->edge[1] (???)
..sorry, I had typed that question in before I tried the code. In my particular case (loading .obj files from disk and triangulating the Ngons and reversing the winding order to show up in C4D correctly...) what I actually needed was two edges from the last triangle (0,2), two edges from the first triangle (0,1) and just the middle edge (0) from the other triangles.
But it's still not working. And in fact, I'm crashing the app with what I'm doing....sigh. -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 16/03/2006 at 03:12, xxxxxxxx wrote:
The NgonBase is created only if Ngons are needed (to save memory), a way to force this to be created when you have no ngons but will be needing to add them is to call GetNgon. Once that has been called then GetNgonBase should return a valid pointer provided everything went ok. (see Modeling Library in the SDK docs)
Edges are defined as the polygon index * 4 + (0 to 3) for each edge around the quad (see PolyInfo in the SDK docs). Building the ngons from what you have is just a case of passing the BuildNgonFromPolys the array of polygons and then an array of edges that form the outline of the ngon.
The outline edges are easily found from the vertices using the Neighbor class. Take the first vertex in your array and use GetPointPolys to find all polygons associated with that vertex, then look at each one and find the edge that matches to the next vertex in your array, that will give you the edge. Repeat this around your vertices and you'll have an array of the corresponding edges. The outline array must be ordered so each edge is the next one around the ngon.
You could also use the modeling library, delete all polygons that are part of each ngon and use CreateNgon with the vertices you have to rebuild the ngons. The Modeling library will then triangulate them itself on Commit. -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 16/03/2006 at 03:20, xxxxxxxx wrote:
Sorry for the spam-fest :)... I'm just at a loss for what's going on. Has anyone ever used BuildNgonFromPolys() successfully? I'd realy like to use that, because as far as I can tell, other methods of creating Ngons will end up re-ordering my vertices and/or polygons (which would break morph targets = a bad thing ).
Would it be possible to get any sort of (known to be working) example code that uses BuildNgonFromPolys()? This is just taking far too much of my time (and yours, I presume) trying to devine meaning from the given documentation in present form.
If it was just for me, I'd just blow off this feature all together (I don't need Ngons for my purposes - or this frustration), but I made a promise (to Maxon) to update Riptide to work with R9 and Ngons, so.... here we are.
Your help is and has been much appreciated - thanks,
- Keith -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 16/03/2006 at 03:22, xxxxxxxx wrote:
Good Morning David.. we cross-posted.. let me read through your latest reply and see if anything clicks.
Thanks,
- Keith -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 16/03/2006 at 04:02, xxxxxxxx wrote:
I did a search and could find no use of BuildNgonFromPolys in any CINEMA core source, it looks like an unused function. Reason is probably that is easier to use BuildNgon since you don't need to pass a list of polygons, just the outer edges or internal edges (in your case outer is easier to find). Both functions are actually just helpers, you could also just use the Create function and build the ngon edges yourself; however this means adding in the correct marked bits but in your case this is much easier since you have no holes.
Generally it is much easier to use the modeling library and leave it to deal with the internal ngon data, however, in some case (like import when you have the polygons already) or generators (where you need speed) you have to use the direct ngon library itself which is more complicated.
First thing to get right is to build your edge outline as I mentioned, once you have this then you have options on how to build/create an ngon. If you only need to keep your vertex order then you can use the CreateNgon of the modeling library, this will not change your vertex order. The modeling library always tries to keep the order of anything it can, even on deleting vertices it will only remap those that it needs to in order to fit the new point count. If you need to keep your polygons and vertices then you'll have to build the ngon manually from the edges.
Here is a small cut of source that uses BuildNgon for import:LONG ngon_start=0,ngon_end=0,eind=0,lastface=NOTOK; LONG *edges = (LONG* )GeAlloc(sizeof(LONG)*4*polyanz); PolygonObject *pObj = obj; pObj->GetNgon(); // necessary to build variables NgonBase *pNgons=pObj->GetNgonBase(); if (pNgons && edges) { pObj->Message(MSG_UPDATE); LONG i=0; for (t=0; t<=fmax;) { if (t<fmax) { f=(WFFace* )group->face.Get(t++); if (!f) { SetError(); break; } anz = f->fnum; } else anz = 3; if (anz==3 || anz==4) { if (lastface==NOTOK) lastface = f->realface; if (t==fmax || f->realface!=lastface) { if (ngon_end-ngon_start>1) { if (pNgons->BuildNgon(edges,NULL,eind,0,pObj->GetPolygon(),pObj->GetPoint())==NOTINDEX) { // error } } if (t==fmax) break; ngon_start=ngon_end=i; lastface=f->realface; eind=0; } if (f->bits&1) edges[eind++] = 4*i+1; if (f->bits&2) edges[eind++] = 4*i+0; if (f->bits&4) edges[eind++] = 4*i+3; ngon_end=i; i++; } t += anz; } pNgons->InitMap(); pNgons->SetFlags(NGON_FLAG_NOVALIDATION); pObj->Message(MSG_UPDATE); } GeFree(edges);
Note the NGON_FLAG_NOVALIDATION is set prior to a MSG_UPDATE to inform the ngon handler that it does not need to check any of the structural changes to the object since the ngons are known to be valid. When ngons are found and MSG_UPDATE is called without this flag set then the ngon handler must check all polygon changes have no invalidated the ngon structures, if they have the invalid ngons are removed. This overhead is costly so it should be avoided when possible, e.g. on import when you know the data is correct.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 16/03/2006 at 04:26, xxxxxxxx wrote:
Hmm, Since BuildNgonFromPolys() is not being used anywhere, I wonder if it might be broken (or further mis-understood/documented)... anyway, I should hit the sack, so I'll take a look at the modelling library stuff after some sleep.
Thanks again!
ZZzzzzzz...
- Keith -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 16/03/2006 at 10:02, xxxxxxxx wrote:
Ok, got a few hours sleep and... Success! (yay)
The final two changes I needed were:
1. I had been using:
*pEdge++ = (pNgons->polys[ndx] * 4)+2; // edge #2
...in a spot where I needed to be using:
*pEdge++ = (pNgons->polys[ndx] * 4)+3; // edge #3
(this is the first time I've messed with edges, so I missed that detail of how triangles are treated vs quads)
2. I switched from BuildNgonFromPolys() to BuildNgon().
...As far as I can determine, I had been passing in the correct polygons in the correct order, but BuildNgonFromPolys() was just not working (even after fix #1 above).
Thanks for bearing with me on this and all the help!
- Keith -
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