This is great! There is, however, one potential issue with this implementation stated here:
"Faces are sorted back-to-front in a very approximate way according to the Z centroid".
In certain cases, this can lead to showing the back face and hiding the front face because the centroid position is not sufficient for figuring out the Z order of triangles.
Other than this minor issue, it's a great implementation.
Centroids is a reasonable approximation, if your geometry is not very coarse. PlayStation games often used this because the hardware lacked a depth buffer.
You're right! The min positions won't resolve the issue either and, unfortunately, there is no trivial fix for it.
Handling intersecting polygons, as you said, is a bit more complex, but for overlapping polygons it's possible to find the Z-order robustly by computing the intersections with the line of sight.
perhaps you could preprocess the shape using the Binary Space Partitioning (BSP) algorithm. there’s a step in the algorithm that finds polygons that would cause z-sorting conflict and splits them along the exact line you need to resolve the conflict. you end up with a data structure that gives you the z sorting order for any camera angle.
For triangles only the intersection case matters. General Polygons could be a bit more complicated. As long as the object is watertight, it's easier.
I recently ran into similar problems to be solved in Python, because I am trying to build a replacement for OpenSCAD by duct-taping together various Python packages. Shapely is quite useful for 2D geometry (like intersection and stuff). PyMesh is extremely useful for 3D meshes, but hard to build.
There are some non photorealistic rendering (NPR) options for Blender, many of them implemented in Python. I don't know if they can output SVG data currently.
ThreeJs has an SVG engine, meaning a backend that outputs SVG.
Thank you for the suggestion. I hadn't seen that yet. From a cursory look it's not completely what I am looking for, but maybe it can be useful.
One of the problems for me is that I am sort of stumbling into this "CAD" thing from a coding perspective. CAD programs like Fusion 360° or FreeCAD seem a bit too complicated for me, and through my grappling with the concepts I am reinventing some concepts/tools.
Particularly I want to develop 3D printed objects the same way I would do data science: Start with Jupyter notebooks, iterate, maybe end up with parametric Python scripts.
If you have only one camera angle, you can certainly do polygon intersection to avoid dealing with overlapping polygons.
It's not necessarily going to be as efficient (or rather, as hardware-acceleratable) as computing Z at each point and maintaining a Z-buffer, but that would assume a fixed resolution.
Very nice! This reminds me a bit of Michael Fogleman's 3D Line Art Engine [0]. His project was motivated by a desire to make vector art for a pen plotter, so not quite the same goals. I appreciate how you've woven together images, code, and explanatory text in this post.
I wish I could find it, but a while back there was a post about a web-based vector renderer for 3D objects, possibly a three.js plugin. It has some really nice looking demos.
I don't think it was seen.io, but seen.io appears to do something similar to this post, in JS: http://seenjs.io/
Outstanding documentation quality - simple descriptions of the context, problem and solution, at increasing levels of specificity. Other people should learn from this when writing their own Readmes.
Yeah this is crazy neat but the unnecessary precision is a real bummer that could be solved by just restricting things to three decimal places. For example when I use a utility like https://jakearchibald.github.io/svgomg/ to optimize, I see a 3.53k -> 2.21k reduction for the sphere with lighting. This is not just from precision reduction but also using simple paths over polygons ... there could likely be increased size savings by "rolling up" the fills in the final output.
Still a crazy neat tool but targeting edges as paths instead of polygons would save quite a few bites when hosting this stuff.
I have thought about doing something similar for PDF reports in a CAE app. Concluded it won’t scale. I need to handle high-poly meshes, 1M vertices and more. That’s why instead I’m using 600DPI jpeg images, rendered on GPU.
But when you know the mesh is low-poly, the technique is really cool. It should be trivial to port from Python to any other language, also from SVG to e.g. PDF.
When I did 3D printing, I racked my brain how to render STL files to SVG. Blender (can import STL and) seems to be able to render to SVG with a plugin (https://blender.stackexchange.com/questions/23661/render-3d-...) but I was never so happy about the results. This small Python code is really so much better!
BTW I always think this website is something to do with being Out and Pride. That is my default parsing no matter how many times I've seen cool stuff on this website and the great stuff that Philip does.
I was thinking that svg would get you better browser support, but it turns out it just gets you IE9/10 and Opera Mini. Which might be important for business apps, but I guess not for everyone:
I know little about modern web development, but I think WebGL is way more efficient on clients.
Even on mobiles, GPUs have much more computing power. They have architecture designed for transforming vertices and computing lightning, very fast and highly parallel.
In best case, SVG will take input triangles and submit them to GPU. Very small overhead (slightly more GPU bandwidth because lightning, when it’s that simple, bandwidth is often more expensive than compute). But in worst case, SVGs will rasterize on CPU, very slow in comparison.
If you rasterize on the server e.g. send jpeg images to browser, it becomes complicated, and depends on many factors like scene complexity and server hardware. Rasterizing triangles is much cheaper on GPU, but JPEG compressor needs data in system RAM not in VRAM, need to download back, relatively slow. Also on many public clouds virtual GPUs are expensive.
Is it really more power-efficient? CPUs are often a smaller process node than integrated GPUs and it's much easier to share common work between pixels with CPU rendering, reducing redundant operations.
I would expect huge difference for similar operations. Current-gen $300 GPU consumes 120W doing 4.6 TFlops. Current-gen $300 CPU consumes 65 W doing 16 flop/cycle * 3.6 GHz * 8 cores = 0.4 GFlops. GPU cores don't spend electricity minimizing latency e.g. predicting branches, and they work at much lower frequencies.
Also some parts of the pipeline are implemented in hardware (rasterizer, texture units, alpha blending, Z buffer), they don't cost flops and hardware implementation is likely even more efficient than shader cores. E.g. if you want a gradient, load/compute per-vertex colors and the rasterizer will interpolate in hardware.
"Faces are sorted back-to-front in a very approximate way according to the Z centroid".
In certain cases, this can lead to showing the back face and hiding the front face because the centroid position is not sufficient for figuring out the Z order of triangles.
Other than this minor issue, it's a great implementation.