Hard Light Productions Forums
Off-Topic Discussion => Programming => Topic started by: Aardwolf on April 05, 2010, 04:04:16 pm
-
Updating the first post and retitling the thread:
Thread for discussing my CSG thingy.
I also created an IRC channel on esper (same network as #hard-light), it's #aard-csg (http://tinyurl.com/24jpqf5).
So I wanted to implement CSG (Constructive Solid Geometry), and I wanted it to be efficient enough to do it in real time (in a game, or at least in a level editor with tolerably un-slow results.
But it's not exactly fast enough. It took about a minute (<< a "guesstimate") just to find the edge/triangle intersections, and that was only for a 148-tri mesh and a 180-tri mesh.
That's unacceptably slow. In fact, it's so slow I can't start working on the re-triangulation code, or the part to get rid of the triangles that are on the wrong sides.
:(
-
I wrote a clustering algorithm for the triangles. It took a lot of additional infrastructure to make it possible, but now it (semi-randomly) selects regions of neighboring triangles with similar normals (maybe just using position would have been better?). Except that's still a separate system from the edge test stuff, and I still have nothing toward cutting the triangles or tossing the bad ones.
Nobody cares? Bah.
-
...
Aard, are you saying that you've essentially implemented booleans into a sim environment? If so, I do think that's quite interesting. Do you have any images you can show us?
-
It can definitely be done, as Solidworks uses it and I know that runs in near real-time on my (rather old) PC.
(Definitely generates the mesh in a few seconds)
Algorithm-wise, I dunno. Too much pure mathematics for me to wrap my head around quickly.
-
No Thaeris, unfortunately I'm not there yet. And I don't know for sure if I'm going to be able get it working any time soon, either... especially considering classes for the new term have just started up.
-
For the idiots who stand in awe(like me), a clarification...
this would, if it comes to fruition, allow beam fire to bore holes and chop things into pieces without predetermination on the part of the model creator?
-
Well, the same concept could hypothetically be applied to FreeSpace, yes... or any game, for that matter. To clarify, though, what I've been doing here has not been related to FS2Open (and in fact has not even been in the same programming language)
-
I've seen a few programs that can do CSG very well indeed, but most of them are not speed-critical, Lightwave, Vue D'Esprit etc all have powerfull boolean setups, but the problems arise, from what little I can remember, when trying to do this with optimised graphics data, I seem to recall that FS2's lack of geomodding is to do, in part, with the way the models are stored, but this was mentioned several years ago, so I can't remember the details.
Vue in particular is good, because it's a real-time CSG, similar, I think, to 3DS Max, if you create a boolean with two objects, the system doesn't just subtract one from the other (or whatever the operation is) and store the results, it actually keeps the two objects that are interacting, and you can alter the boolean effect by moving/resizing the objects involved. The negative side of this is that it only works with basic shapes, i.e. Spheres, Cubes etc, whereas Lightwave can boolean anything with anything else as long as there are no points that are in precisely the same place in both sides of the operation (and with the usual problem associated with CSG operations, like problems with complex objects).
-
I noticed while doing some research on the subject: some programs use the stencil buffer to do screen-space CSG. A depth buffer is all that's really needed to do a Boolean Union (although you still have lots of overdraw, and hidden/wasted geometry), and for "cut" surfaces, that's where the stencil buffer comes in.
As I haven't made much progress on my implementation, I'm not how (or if!) I will proceed now.
-
A little more work (you might even call it "progress"!) and a thread bump.
I wrote a little sub-algorithm to do some pre-processing in order to figure out which parts of the meshes are nowhere near intersecting, and which are closer. I think it might not be as efficient as it could be, and it didn't cull as much as I would have hoped...
Here's what it determined "might intersect" out of a pair of 180-faced geospheres:
(http://i93.photobucket.com/albums/l77/Aardwolf001/Quick%20Illustrations/geospheres_crunch_region.png)
The way I'm doing it is I'm computing a 3d grid (for each mesh), where each point's value is the (shortest) distance to the object. I then check the other mesh's vertices against that mesh, and see how far they are. If the edge lengths of that mesh's triangles exceeds the distance, it's a "maybe intersecting" triangle. Otherwise, it's safe (not in need of intersection tests / cuts, but possibly one of the triangles that must ultimately be removed). Unfortunately, the computation of the distance is more expensive than I'd like (with a 16x16x16 grid, the whole thing takes a second or so), and the amount of culling that's getting done might not be worth it.
I'm thinking I could store additional data somewhere (specifying which triangles are near others) to speed up the process, but I'm not sure... maybe I'll just try to do the cutting/intersection tests with what I've got here, and get that working.
-
Can you give more information on how you're 1) Doing the collision and 2) Applying the collision information.
There are thousands of papers out there on this kind of thing - ACM Digital Portal is a really good place to start.
Collision and vertex level operations are some of the most difficult to do quickly and efficiently.
I think you've got yourself a fairly brute force algorithm - they're always slow unless they're optimal (d'oh!).
Maybe try something along the lines of BSPs? Precomputed, of course.
-
Originally I was trying to brute-force it, but I realized that was silly and tried doing something with clustering, but I dropped that approach...
Currently I'm planning on just getting some reasonably un-slow output, and then I'll tweak the steps between the input and that. By 'tweak' I of course mean using better algorithms, not funroll-loops (lol)
Edit, rather than yet another shameless double-post:
I've redone that part of the algorithm once again... it now uses an octree (evenly split, though, rather than using some 'intelligent' splitting, and it's got a predetermined max depth of 5 IIRC) where each node contains a list of all the triangles from each object (so two lists really) (by index) whose bounding boxes (i.e. the bounding box of the triangle) intersected that cell of the octree. I also realized that the only place any intersections were going to happen was within the intersection of the two objects' bounding boxes, so I set that as the initial bounds for the octree (i.e. the root 'box' of the octree)...
With my current test case, my algorithm now correctly culls the number of triangles that must be compared from 180x180 down to 97x8... that's a 4175% improvement :D
Edit! Stop the presses!
Upon closer inspection, there are 97 triangles from the first object which have 1 or more triangles to test against, and 8 from the second object. But the actual number of triangle pairs to test is only 213, meaning my algorithm only has to do 1 / 152.113 as many triangle pairs as I would if I were to brute-force it!
Edit, again (since I'm editing it's not bumping the thread, I hope people notice it anyway!) :
I've got the edge intersections thing working ok now, but the re-triangulation ... not so much. I think I'll maybe go ahead and put in the part to eliminate the ones on the wrong side, anyway, and then go back and fix up the problems with the re-triangulation.
(http://i93.photobucket.com/albums/l77/Aardwolf001/Quick%20Illustrations/Screenshot-2010-4-12-16-24-56-951.png)
-
I don't know much about this stuff, but what's the difference between this and collision detection? Are they similar to each other and could your work here be used to improve collision detection in the game?
-
No, it's not really similar to collision detection, although it does require some sort of collision detection to work. It's basically trimming two intersecting polygon meshes (or in my case, they are specifically triangle meshes)... cutting them at the intersections and removing the stuff that's outside/inside/whatever.
Technically, CSG is supposed to be about the actual solid region enclosed within the polygon meshes combining, but it's not feasible to deal with the volumes... much better to find the intersections of the polygon meshes, cut them there, and toss the junk.
Also, I've run into a bit of a snag with the retriangulation... my algorithm isn't working right, and I'm thinking now that I really want it to be working right before I move on to the removing-inside/outside/whatever triangles part.
Help would be appreciated!
Edit (technically edit 2):
I've formulated (in text) my problem:
BasicModelVert struct has:
* A Vec3 position
* A Vec3 unit normal vector
* A Vec2 texture coordinate
Given...
* The three vertices of a triangle, each with position, vertex normal vector, and texture coordinates
* A list of cuts through the triangle; each cut is a line segment stored as two vertices of the same type as above
...output is a list of triangles, such that:
* The only used vertices are those from the original triangle and the cuts through it
* All of the original triangle's edges (split where intersected by the 'cuts') are present as edges
* All of the line segments of the cuts are present as edges
* There are no degenerate triangles
* The entire surface of the original triangle is covered by the output triangles
* The output triangles do not overlap
Ideally, the output also has as little "squashing" of triangles as possible
So, any ideas?
Edit, again:
I've almost got it. But now I need to solve this graph theory problem:
I've got a graph. Each node has an associated boolean value. i'm trying to find all the possible setups (i.e. i want a list of bool[n]) such that: no true node neighbors another true node, and every false node neighbors at least one true node.
Alternative phrasing of the same problem:
I've got two colors (true and false) and a rule about how they can be placed in the graph; I need an algorithm to iterate through / list all of the colorings that satisfy this rule (given the uncolored graph).
And since people've gotten confused a lot about what I'm looking for:
Input: number of nodes, and which nodes have edges between 'em. Output: a list of each and every valid array of booleans.
-
Yay! It's sort of working.
But as these screenshots will illustrate, it's still a little buggy:
(http://i93.photobucket.com/albums/l77/Aardwolf001/Quick%20Illustrations/Screenshot-2010-4-18-14-17-30-98.png)
(http://i93.photobucket.com/albums/l77/Aardwolf001/Quick%20Illustrations/Screenshot-2010-4-18-14-17-23-161.png)
(http://i93.photobucket.com/albums/l77/Aardwolf001/Quick%20Illustrations/Screenshot-2010-4-18-14-17-14-46.png)
Note that these are screenshots picked specifically to point out the bugs. It's not always made of fail.
Also, the normals for the 'cut out' region are inverted. I'll fix that eventually too.
-
Finally got it working!
Screenshots:
(http://i93.photobucket.com/albums/l77/Aardwolf001/Quick%20Illustrations/Screenshot-2010-4-24-17-19-36-205.png)
(http://i93.photobucket.com/albums/l77/Aardwolf001/Quick%20Illustrations/Screenshot-2010-4-24-17-20-30-246.png)
(http://i93.photobucket.com/albums/l77/Aardwolf001/Quick%20Illustrations/Screenshot-2010-4-24-17-22-11-765.png)
(http://i93.photobucket.com/albums/l77/Aardwolf001/Quick%20Illustrations/Screenshot-2010-4-24-17-23-36-167.png)
(http://i93.photobucket.com/albums/l77/Aardwolf001/Quick%20Illustrations/Screenshot-2010-4-24-17-23-37-111.png)
-
Nicely done! I won't pretend to understand the maths involved, but congratulations nonetheless, just shows that perseverance pays off ;)
-
That's awesome. When can we expect it for beam damage and destructible stuff in in FSO? .14? .16?
-
That's awesome. When can we expect it for beam damage and destructible stuff in in FSO? .14? .16?
Probably never. This isn't even written in the same programming language as FSOpen and isn't built for in-game use.
Take its awesomeness on its own terms.
-
Haha, probably not any time soon. It's all written in C#, and the engine is in C++/C. It would be possible to port it, but it'd be a hassle, and I hear there are some issues with how the model formats work that might make it difficult as well.
Oo, batts beat me to it.
Edit: hm... I need to do some software engineering :blah:
-
if you recoded the BSP to use an actual tree structure, and wrote code to rebuild that tree structure on the fly, you could put this in FSO.
note: this is actually not as hard as it sounds.
but for performance reasons you would have to run this in a separate thread.
-
It looks great:
(http://i93.photobucket.com/albums/l77/Aardwolf001/Quick%20Illustrations/Screenshot-2010-4-27-16-36-56-261.png)
But there's lots of slivery triangles I gotta get rid of:
(http://i93.photobucket.com/albums/l77/Aardwolf001/Quick%20Illustrations/Screenshot-2010-4-27-16-36-57-758.png)
...preferably without screwing up my UV coordinates or vertex normals. There's a few other things I oughtta fix up, too.
-
pretty cool, but is there any way to stop all the new tris from sharing the same vert? aparently it causes some smoothing and normal maping issues. on the other hand it looks ok from your renderer.
-
Nope, not unless you add more vertices in the parent mesh for them to link to.
-
Well, I could possibly make some sort of polygon reduction algorithm. Or I could add some more verts along the edges... it'd make more triangles total, but they'd be less squashed.
I think the reason mine still looks good is because I'm not re-generating the vertex normal vectors. All of the vertex normals are either the ones from the original meshes, or are those but interpolated (specifically, taking a weighted average of the verts of the original mesh's triangles, and renormalizing it). A model editing program would probably generate the vertex normals after-the-fact, and probably as a flat (i.e. not weighted) average of the face normals surrounding the vertex, thus making it looks stupid. But that's just speculation on my part.
Edit: Or I could somehow combine the added verts with the poly-reduction thing... somehow.
-
Hm, idunno what to do next with this. There's a bunch of things that still need to be done, and I'm not entirely sure what order to do it, etc.
My un-ordered "TODO" list looks like this:
- Speed up existing functionality
- Rearrange the existing functions/classes (there's a bit of redundancy, I think)
- Mesh optimization... Adding more verts to eliminate slivers? Removing unneeded edges? Keeping references to the original triangles/geometry (i.e. quasi- N-gons)?
- Allow more kinds of generalization (without breaking existing stuff)
- Support for more than two operands simultaneously?
- Other stuff?
Advice is welcome!
-
Thread-bump!
My interest in this project is somehow renewed. I've asked a bunch of people I know if they're interested in collaborating on this. Obviously no replies yet.
Edit: Oh hey, I put it on Google Code (http://code.google.com/p/modelthulhu/).
-
just as a stress test, why don't you code up a test where a bunch of random objects are placed randomly then added subtracted from each other.
also a feature you might want to look into is determining if an object has been split into two objects.
multithreading is also another thing you should be making sure is safe.
-
Checking if it's been split into more than one piece? Actually, I think that's almost already in there. That is, it's already finding regions of contiguous faces (stopping when it runs into a cut), and then determining whether those regions are on the correct side of the other object. It probably wouldn't be too hard to modify the code to check for that.
But there's still some major refactoring that needs to be done, and I'm not sure whether that feature is something that should come before or after the refactoring.
By the way, since it's now on Google Code, anyone can check it out. So if anybody wants to become a contributor1 or a committer2, shoot me a PM.
1Lets you comment on the Wiki, Issues, etc. (I think)
2Lets you commit SVN changes