Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CanvasGeometry #3116

Closed
wants to merge 2 commits into from
Closed

Add CanvasGeometry #3116

wants to merge 2 commits into from

Conversation

wizgrav
Copy link
Contributor

@wizgrav wizgrav commented Feb 22, 2013

CanvasGeometry extrudes watertight solid meshes from pixels based on transparency(by default). It's based on a technique I'm researching and, so far, call running image triangulation & extrusion. There is still more to be done but it has already started being useful. The base concept comes from a blob tracking algorithm called run based component labeling. It works by recording continuous horizontal lines(separated by transparency) as pairs of vertices, called runs. While it raster scans one row, it interconnects the runs of the previous one, so most of the work gets done fast in one pass. It produces nice models with low polygon counts. You can see a demo here http://wizgrav.github.com/three.js/runner/ and a (preliminary) paper here http://revoxel.com/runner/paper.pdf

@bhouston
Copy link
Contributor

It is very similar to 2D marching squares (like marching cubes) and it is a common optimization when doing marching cubes/squares to keep track of the previous row to speed up connections.

http://en.wikipedia.org/wiki/Marching_squares

And then one has extruded this result.

I am unsure if this should be in core. But if it is, I'd suggest one algorithm that creates a 2D trimesh of the canvas and then a second part that extrudes it (there is already an extrude geometry in Three.js which you can reuse.)

Could you compare your method with that of Marching Squares? Also I'd even suggest adding an intermediary representation where you extract from canvas a 2D array of points and then pass that into your Marching Squares implementation, this way others can use it even if they are not using a canvas.

One neat thing you can do with Marching Squares is to retopologize the interior to get rid of unnecessary polygons (first convert to one large concave polygon and then process it separating it into maximally size convex polygons) and you can likely also smooth the outside before doing that to get rid of unnecessary edge pieces. This might be a way of converting rasterized fonts into nice 3D meshes in a general way.

@bhouston
Copy link
Contributor

I am impressed with the speed of this and the quality of the results, although there is a lot of triangles in the results. My concerns in the previous comment are mostly about making its pieces easily reusable. I have found 2D marching square useful in the past and I did generate them from Java Drawing2D Canvases in a similar approach.

@wizgrav
Copy link
Contributor Author

wizgrav commented Feb 22, 2013

@bhouston I'll check on marching squares but I suspect that the run based approach should be faster. It could also be possible to optimise the model as well, but I opt on letting the quantization on the y axis as it may have interesting application. The contour information is gathered in one array containing pairs of vertex indices, I'll check if that can be exported into something meaningful for other components to use

@bhouston
Copy link
Contributor

@wizgrav Ah, I see. I misunderstood what you meant by runs. It would be faster than marching squares then. It is like marching squares but with arbitrary sized rectangles that vary based on feature size. Very neat actually.

I'd still suggest separating the algorithm into a few pieces. The first would create the connected outline, the next would turn it into a solid polygon, another would extrude it. You can reuse the existing ExtrudeGeometry and if you find you can optimize please do! I think there is already code to polygonize an outline in the code base, it was written by @zz85. Thus basically you would provide the canvas to connected outline code.

I guess I personally prefer algorithms decomposed into reusable pieces so we can combine them in new forms, rather than having somewhat fixed functionality, which is less useful. Also having decomposed algorithms makes it easier to test and see what is going on even if it can be slightly slower.

@wizgrav
Copy link
Contributor Author

wizgrav commented Feb 22, 2013

@bhouston I checked on ExtrudeGeometry. It would be nice and feasible for the contour shape to be extracted and reused with that as well. I'd appreciate it if @zz85 could help me a bit with that. I'd like to also keep the one pass method, for performance reasons

@wizgrav
Copy link
Contributor Author

wizgrav commented Feb 22, 2013

Did some more research on THREE.Path and Shape and I see that producing something generalized will be trickier than I thought. The algorithm keeps track of the contour and could produce lineTo commands for Path. The first issue is that extrude geometry needs array of distinct features(paths) along with the holes definition as distinct paths. There will be some more bookkeeping needed to keep track of the connected components but the algorithm already has that potential. The hole matching could be tricky but feasible as well. Another issue is that THREE.Path.prototype.fromPoints expects points in the order of every feature's contour whereas in CanvasGeometry they're produced on a horizontal scan order for all features. Grouping and reordering these would kill performance without benefit on polygon counts. I'd really appreciate some insight from @zz85 on this

@zz85
Copy link
Contributor

zz85 commented Feb 22, 2013

this seems interesting, it might be useful for extruding pixel art for example. haven't look in detailed into this, but like @bhouston says, seems to be generate a large amount of faces.

THREE.Path, THREE.Shape are kinda vector representations, and ExtrudeGeometry uses a triangulation process (which could be improved on) which turns them into triangles. Since the triangulation method seems to close r to the other approaches mentioned in your paper, i'm not sure if ExtrudeGeometry would be suitable for your case, unless you are able extract and simplify vector paths from the raster image using your algorithm.

@wizgrav
Copy link
Contributor Author

wizgrav commented Feb 22, 2013

@zz85 the amount of generated vertices/faces is bound to the y resolution of the image so it can be controlled from that. You can also rotate the canvas to control the direction of the vertex quantization. This comes handy if you'd like to bend or wrap the model around something else.

In a sense this is a fast triangulation algorithm that works with an ordered grid as input. Vectors could be rasterised and then triangulated with CanvasGeometry. This may actually be a good choice in HTML. You could load an svg on an img at the resolution you desire(taking advantage of the native path performance), then drawImage and run it to produce a model. Unfortunately this won't work on chrome currently due to a bug that taints the canvas origin flag when loading svgs even those from the same domain http://code.google.com/p/chromium/issues/detail?id=68568

As far as vector extraction is concerned all the vector pairs for the sidewalls are stored along with their 2d normals. The problem is that these are arranged on a row by row basis. The array contains pairs mixed for all the distinct outlines contained in the image. These would have to be grouped and reordered to be useful to a convex polygon triangulator. This step will be very expensive so I'm not sure if it's worth the effort. This method was not really designed to perform tracing

@wizgrav
Copy link
Contributor Author

wizgrav commented Feb 22, 2013

@mrdoob what would be the most appropriate way to attach custom data on a geometry. I want to export the outline data, should I use a _metadata property on the geometry or is there something more specific?

@mrdoob
Copy link
Owner

mrdoob commented Feb 23, 2013

Object3D has the object properties. We could add that to Geometry and Material too. But I'm hesitating about the naming. Maybe userdata illustrates better the purpose?

@wizgrav
Copy link
Contributor Author

wizgrav commented Feb 23, 2013

Updated http://wizgrav.github.com/three.js/runner/ example with options to tweak the canvas before running

@bhouston
Copy link
Contributor

I like userData. We would fine it useful as well.

Sent from my phone, sorry for my grammar and terseness.
On Feb 23, 2013 4:27 AM, "Mr.doob" notifications@github.com wrote:

Object3D has the object properties. We could add that to Geometry and
Material too. But I'm hesitating about the naming. Maybe userdataillustrates better the purpose?


Reply to this email directly or view it on GitHubhttps://github.com//pull/3116#issuecomment-13987479.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants