mesh->csg stack overflow
jackrusher opened this issue · comments
(-> (cuboid 80)
(g/as-mesh {:mesh (gm/gmesh)})
csg/mesh->csg)
... works as expected, but if I try to catmull-clark the mesh before converting to CSG, like this:
(-> (cuboid 80)
(g/as-mesh {:mesh (gm/gmesh)})
sd/catmull-clark
csg/mesh->csg)
... I get this stack overflow:
RT.java: 721 clojure.lang.RT/get
csg.cljc: 58 thi.ng.geom.mesh.csg$split_poly/invoke
csg.cljc: 143 thi.ng.geom.mesh.csg$csg_node$fn__18902/invoke
PersistentVector.java: 333 clojure.lang.PersistentVector/reduce
core.clj: 6518 clojure.core/reduce
csg.cljc: 142 thi.ng.geom.mesh.csg$csg_node/invoke
... do more complicated meshes push the recursive csg-node
function too deep?
Hi @jackrusher - there definitely is a point where a complex mesh will blow the stack, but it shouldn't be after 1 iteration of subdivision. Will investigate! Thanks
So, the thing works if you pre-tessellate the meshes. This makes me think that there're might be some issues with face normals in the original quad mesh. Because the face normals are used to define cutting planes in the BSP construction, if there're invalid values (e.g. two neighboring faces with opposite orientations), then the BSP construction will go into an infinite loop and blow the stack...
(require '[thi.ng.geom.cuboid :as c])
(require '[thi.ng.geom.gmesh :as gm])
(require '[thi.ng.geom.core :as g])
(require '[thi.ng.geom.mesh.csg :as csg])
(require '[thi.ng.geom.mesh.io :as mio])
(require '[clojure.java.io :as io])
(def m (-> (c/cuboid 80) (g/as-mesh {:mesh (gm/gmesh)})))
(def m2 (sd/catmull-clark m))
(def m3 (last (take 4 (iterate sd/catmull-clark (g/translate m [60 0 0])))))
(def m4 (apply csg/union (map (comp csg/mesh->csg g/tessellate) [m2 m3])))
(with-open [o (io/output-stream "foo.ply")]
(mio/write-ply (mio/wrapped-output-stream o) (csg/csg->mesh m4)))
Btw. The 4 iterations of subdivs seem to be the maximum for this example. With 5 it throws a different SO, but this time it has to do with concat's laziness...
#error {
:cause nil
:via
[{:type clojure.lang.Compiler$CompilerException
:message "java.lang.StackOverflowError, compiling:(form-init8102643818965635375.clj:1:9)"
:at [clojure.lang.Compiler$InvokeExpr eval "Compiler.java" 3628]}
{:type java.lang.StackOverflowError
:message nil
:at [clojure.core$seq__4128 invoke "core.clj" 137]}]
:trace
[[clojure.core$seq__4128 invoke "core.clj" 137]
[clojure.core$concat$fn__4215 invoke "core.clj" 691]
[clojure.lang.LazySeq sval "LazySeq.java" 40]
[clojure.lang.LazySeq seq "LazySeq.java" 49]
[clojure.lang.RT seq "RT.java" 507]
[clojure.core$seq__4128 invoke "core.clj" 137]
[clojure.core$concat$cat__4217$fn__4218 invoke "core.clj" 700]
[clojure.lang.LazySeq sval "LazySeq.java" 40]
[clojure.lang.LazySeq seq "LazySeq.java" 56]
[clojure.lang.RT seq "RT.java" 507]
...
Proposed fix: Avoid concat
calls in csg/clip-polygons
& csg/all-polygons
, use into
or reducers' cat
Thanks, mate. Having fun with CSG now!
Great! :) Looking forward to see some of that - alas due to the current major mesh refactoring, there's no point in attempting to fix the above in master before the other things have settled