The SVG Loader in threejs
There are a number of options for additional asset loaders in the Github Repository of threejs, one of which is the SVG Loader. Which is a way to go about loading a SVG file asset as an external file into a threejs project as a collection of paths that can then in turn be used to make Shapes. These shapes can then be used with somehting like the Shape Geometry or the Extrude Geometry constructors.
The SVG Loader and what to know first
There is a lot that one will need to be aware of before hand when it comes to using these source code examples that I am writing about here. As always I assume that you have at least a little experience with client side javaScript and the underlying skills that are needed on top of that with HTML and CSS. However on top of that there are also a great deal of other features in the threejs library alone that you might want to play around with a little first also. I will of course not be getting into great detail with all of this in this post, but I will at least mention a few things in this section before getting into the first SVG Loader example.
There is also knowing how to go about making an SVG file first
Although it might be best to still use some kind of image editor to create SVG Graphics, it is still possible to edit the values of SVG with just a plain old text editor as well. Whatever the case may be when it comes to making the SVG assets that you will like to load into threejs by way of the SVG loader, getting into every little detail about SVG is outside of the scope of this post. A few years back I wrote a post on getting started with SVG from the ground up which might prove to be a good starting point. There is also the Modzilla Docs on SVG that do a great job covering everything with elements and attributes of SVG.
More than one file to use beyond just that of threejs alone
In these examples I am using more than one extral file beyond just that of the core threejs library. For one thing the SVG loader itself is not baked into the core of the threejs library, but rather it is an additional optional loader that can be found in the examples folder of the threejs github repository. So I am linking to the threejs library and the SVGLoader.js file as well just when it comes to official code from the repo on Github. On top of that I am also linking to my own javaScript files on an example by example basis, and of course I am also loading one or more SVG files as well.
There are also my posts on my SVG tools, and SVG movement threejs project examples
I have made a number of threejs project example posts and two projects that are relevant to using the SVG loader are my SVG movement, and my SVG tools projects. The SVG movement has to do with using svg files as a way to define paths in space that are used to move objects around. The SVG tools project is a more generic module that has to do with using SVG in general to create Logos and such.
Source code and SVG assets are up on my Github
The source code examples that I am writing about here, as well as the SVG assets, and additional notes and files can be found in my test threejs repository up on Github. This is also where I place the source code examples for the many other blog posts that I have wrote on threejs over the years.
Version Numbers Matter
When I first wrote this post I was using r140 of threejs which was released in May of 2022. Also the last time I came around to do some editing I updated the source code examples of all demos to my r146 style rules which at the time is the oldest style rules I am observing at the time. There are a whole lot of code breaking changes coming up ahead. Also I think that I should state that with the source code examples here I am using the plain javaScript file form of the SVG loader as well as with various other asserts like the buffer geometry utils and so forth. This is because with my r146 style rules I observe that these files are still there to work with, while that is not the case with more up to date style rules that I have in the works.
1 - Basic Shape SVGLoader demos
As with all of my posts on threejs I like to start out with some simple getting started type examples. So in this section I will eb starting out with a few demos that will make use of THREE.SvgLoader, and also THREE.ShapeGeometry. Although I will be doing what I can to make these demos simple there is still a lot to take in with this. Not just with the SVG loader but also additional skills that might be required when it comes to how to go about creating SVG data to begin with.
1.1 - Parse a hard coded SVG String
Although real projects will typically involve loading an external SVG file, if you are wondering if there is a way to load a text string using THREE.SvgLoader there is. The general process of doing so would be to create an instance of the svg loader, but then use the parse method rather than the load method. When calling the parse method I just pass the string that contains the svg data. The end result is then an object that will contain paths data, this can then be used with the create shapes method of the SVG loader to create shape objects. Once I have a shape object I can then use that with TREE.ShapeGeometry.
|
|
1.2 - Using the load method and THREE.ShapeGeometry
Often I will want to use the Shape Geometry constructor as a way to go about adding svg to a threejs project. So then one way or another I will need to crate one or more Shape objects from the SVG data when loading an SVG file. The good news with this is that there is a static method of the SVG loader to help with this process.
So then when I create an instance of the SVG loader and call the load method of it, in the body of the callback function that I give the load method that will fire the file finishes loading I will have a data object. This data object will contain a property called paths that will be an array of ShapePaths. I can then loop over this paths array then and pass each instance of shapePaths to the THREE.SVGLoader.createShapes method, the returned result of this will then be an array of Shapes. I can then loop over this array of shapes and for each shape object I can use that as a way to create any kind of buffer geometry with a buffer geometry constructor that will take a shape as an argument, such as the THREE.ShapeGeometry constructor.
For this example on making shapes from loaded SVG data then I have a helper function that will create and return an array of shape geometries. I then have another helper function that will create an array of mesh objects by calling this other helper function that creates the array of shape geometries, then making a mesh object for each of them.
For this example with the create mesh objects helper I am using the basic material for starters. Each time I create the instance of the basic material I can use the color data from the svg for each path for setting the defuse color for each basic material. Sense these are 2d shapes that I am adding into threejs I might want to set the depthWrite property to false. Also it would be a good idea to set the side property of the material to the THREE.DocubleSide constant.
|
|
2 - Merge Geometry Example
When it comes to loading in SVG data often I will have more than one shape, that will result in more than one shape geometry. This will also mean that I will need to have a group of mesh objects for each shape. Although in many cases this will work fine, and in some cases it will actually be what I want to happen, there may be some situations in which I will want to merge all these shape geometries into one single geometry.
One way to do this is to use the merge buffer geometries method of the buffer geometry utils. This buffer geometry utils is yet another feature that is not baked into the core of threejs itself but must be added by loading an additional external file on top of threejs that can be found in the threejs Github repo.
|
|
3 - Extrude Geometry Example
There are other options for creating a geometry from a shape other than that of the THREE.ShapeGeometry constructor, one of which would be the THREE.ExtrudeGeometry constructor. This allows me to create a geometry that is like that of the 2d plain kind of shape of the shape geometry, but I can add a depth option that will extrude out the 2d shape. I have found that when doing so I want to disable bevel and also adjust the options for curveSegments and steps.
|
|
4 - data textures, and custom uv generator
So at this point I have covered the basics of using the SVG loader, and that there is creating extrude geometry which is one option as to what can be done with the loaded data. I have all ready covered a basic example of using extrude geometry that seems to work okay, but there is just one little problem that comes up when trying to add some texture to the geometry. With that said I will some times need to work out a custom way to generate the UV attribute of the extrude geometry.
Also speaking of textures one way or another I will need to create some textures to use with the materials that will be used for the mesh objects. There are many options for this sort of thing such as also using the texture loader to load in textures that are in the from of external image files. However there is also a few ways to create some texture by way of a little javaScript code such as canavs textures, or for the sake of this example data textures.
4.a - Data textures module
This is what I have together for a general data texture module that has been serving me well thus far in various projects. I have a few options here that allow for me to create a data texture on a pixle by pixle basis, one such method I can all directly, and another I can give data that is a color index for each pixle location called fromPXDATA. I have another function that uses the THREE.MathUtils.seededRandom method as a way to create a random noise texture.
|
|
4.1 - Main javaScript file
So the general idea here is to create some textures, and also to come up with a custom UV Generator functions for the extrude geometry that will be used with the SVG data.
|
|
5 - Just working with Paths
In this section I have worked out a number of examples that have to do with just working with the paths data for doing all kinds of various not so typical tasks with SVG data. That is that often I will want to just create a single geometry, or a group of geometries from the SVG data to make one or more mesh objects. However in some cases I might want to do something else with the path data that is not so typical.
5.1 - Box3 from Path
One thing that can be done is to create an array of points from the path data by which I mean an array of THREE.Vector3 class instances. After doing so I can use this kind of array to create a buffer geometry by making use of the set from points method of the buffer geometry class. Once I have a buffer geometry class I can do something like call the compute bounding box method to get an instance of Box3 that I can then use with the box3 helper.
|
|
5.2 - create mesh objects for each point
So making a buffer geometry from an array of points and the calling the bound box method of the geometry is one thing. However another thing that comes to mind is to use this array of Vector2 class instances as a way to create a bunch of mesh objects for each point.
|
|
6 - Points
Yet even another options would be to create an instance of Points rather than the usual Mesh objects. When it comes to this I am limited in terms of materials as there is only one option which is the Points Material. The only options that I might set for this kind of material are size and color. As I covered in the above examples in the paths option there is not using points and points material by rather running over the array of vector2 class instances and creating a mesh object for each point. When doing things that way I can use any build in geometry constructor and thus any mesh material that I want.
|
|
7 - Lines
What if I just want to create some Lines with the SVG data, for that one option might be to use the THREE.Line constructor in place of mesh. When doing so I have two options in terms of materials, one of which is the Line Basic material which is what I would typically use. When setting options for the line basic material certain options will only work with certain platforms and renderers. For the most part then it is only color and the fog Boolean that will work for most renderers and platforms.
|
|
Conclusion
The SVG loader is then the official file for loading in SVG data and doing something with the 2d path data that is given in the data result object when loading works fine with the SVG. There is then a number of things that can be done with this 2d path data, that are typical of doing so and also maybe not so typical. For one thing I can do something like create a 2d shape geometry, or an extrude geometry. when doing so things can end up getting a little involved when it comes to getting textures to work they way that I want them to though. There is then also doing things that are maybe not so typical such as using SVG path data as a way to define paths in which I would like to move objects over time. There are all kinds of things that I can do with the array of Vector2 class instances beyond just that of simply making shapes.
Still there are limitations to what can be done with SVG, or things prove to be a little to complex compared to other options. There is not just importing SVG into threejs, but rather importing it into a program like that of blender, and then doing what I need to do in order to create a DAE file from there. In blender I can work out what the deal should be not just with extrusion if that is what I am to do with it, but also it is easier to work out what the deal should be with respect to things like UV Mapping.