Open Mugen87 opened 1 year ago
I had the hope that setting a high value for the number of interpolation points would correct the issue (note the extra 5000
parameter here):
const geometry = SVGLoader.pointsToStroke( subPath.getPoints( 5000 ), path.userData.style );
Unfortunately it does not solve it. I'm afraid it is not addressable in the algorithm as it is written right now. It would require self-intersection tests. On the other hand it is doable in a completely separated 2D algorithm, let me see if I can put up something in the next days.
I tried to make a triangularization algorithm which discards overlapping triangles. But it gives false positives and discards too many. It works in tests but not in the SVG from the example.
Something that came to my mind: Could you utilize the existing Earcut implementation for this use case?
https://threejs.org/docs/index.html#api/en/extras/Earcut
Meaning you first generate the contour (which is just a sequence of points) an then let Earcut do its job.
Thanks for noting it. I will take a look. I will also investigate if I can get the holes indices.
@Mugen87 I've implemented your idea, by holding two contour points arrays (left and right ones) and combining them at the end, giving the full stroke contour.
It works mostly correctly in the use case. I hoped it worked in the general case but you can see that the Tiger.svg has some artifacts. It is caused by the contour I generate, which folds over itself on some corners. Earcut does not like that on complex paths. As before, solving this would require checking self-intersections, but now in the linear contour, not in a triangle soup. It is doable, but only would work if the original path doesn't self-intersect.
Detail of the contour folding over itself:
Tiger.svg:
Use case:
Use case detail:
The algorithm is smaller and cleaner (751 lines down to 495). Performance seems similar as before. The drawback is that the two contour arrays must be allocated. This can be optimized by providing reusable user arrays.
As the whole pointsToStrokeWithBuffers()
is modified, I don't know very well how to integrate this change. For now I've just duplicated the function with the name pointsToStrokeContourWithBuffers()
.
The function pointsToStroke()
accepts a boolean parameter useEarcut
(default false) and selects which function to call.
It seems THREE
doesn't export Earcut
so I've copied Earcut.js
in /jsm
just for testing.
I've tried to make a live preview but failed. You can read the modified loader and example here: https://github.com/yomboprime/three.js/commit/563aea9172ada3e7dfa862e3125334415b40f336
Expecting your feedback to see if this can be useful.
Just an update: There was some bugs in that branch commit. I'm trying to debug some last issues.
Unfortunately I've not been able to solve it for the general case. I've spent many hours on this.
The problem is when the path points do auto-intersect like this (the contour gets flipped over itself):
I think this problem needs more thought than an amateur mathematician (me) can give.
I appreciate your effort on this! Even without a concrete solution the problem is now better understood than before 👍 .
Thanks!
Description
The original issue was reported at the forum: https://discourse.threejs.org/t/glitches-with-svg-loader/46803
SVGs that exceed a certain
stroke-width
are not rendered correctly. As visible in the below screenshot, the resulting shape is rendered with additional triangles on its back side. When decreasing the stroke width (in the below SVG try 200), the issue goes away.I suspect there is a problem in SVGLoader.pointsToStrokeWithBuffers() which generates triangles based on the stroke definition from the SVG.
Reproduction steps
Code
Live example
Screenshots
Version
r148
Device
Desktop, Mobile, Headset
Browser
Chrome, Firefox, Safari, Edge
OS
Windows, MacOS, Linux, Android, iOS