You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This package supports loading 3D model file formats: `obj`, `stl`, `ply`, `off` and `2DM`.
6
+
This package supports loading 3D model file formats: `obj`, `stl`, `ply`, `off`, `msh` and `2DM`.
7
7
More 3D model formats will be supported in the future.
8
8
9
9
## Installation
@@ -22,49 +22,35 @@ This means loading a mesh is as simple as this:
22
22
using FileIO
23
23
mesh =load("path/to/mesh.obj")
24
24
```
25
+
The result will usually be a [GeometryBasics](https://github.com/JuliaGeometry/GeometryBasics.jl)`Mesh`.
26
+
The exception are `obj` files with non-vertex data such as material data or "group" tags, which return a `MetaMesh`.
27
+
25
28
Displaying a mesh can be achieved with [Makie](https://github.com/JuliaPlots/Makie.jl).
26
29
27
30
Functions for mesh manipulation can be found in [JuliaGeometry](https://github.com/JuliaGeometry)
28
31
29
32
## Additional Information
30
33
31
-
MeshIO now has the HomogenousMesh type. Name is still not settled, but it's supposed to be a dense mesh with all attributes either having the length of one (constant over the whole mesh) or the same length (per vertex).
32
-
This meshtype holds a large variability for all the different attribute mixtures that I've encountered while trying to visualize things over at GLVisualize. This is the best type I've found so far to encode this large variability, without an explosion of functions.
33
-
34
-
The focus is on conversion between different mesh types and creation of different mesh types.
35
-
This has led to some odd seeming design choices.
36
-
First, you can get an attribute via `decompose(::Type{AttributeType}, ::Mesh)`.
37
-
This will try to get this attribute, and if it has the wrong type try to convert it, or if it is not available try to create it.
38
-
So `decompose(Point3{Float32}, mesh)` on a mesh with vertices of type `Point3{Float64}` will return a vector of type `Point3{Float32}`.
39
-
Similarly, if you call `decompose(Normal{3, Float32}, mesh)` but the mesh doesn't have normals, it will call the function `normals(mesh.vertices, mesh.faces, Normal{3, Float32}`, which will create the normals for the mesh.
40
-
As most attributes are independent, this enables us to easily create all kinds of conversions.
41
-
Also, I can define `decompose` for arbitrary geometric types.
42
-
`decompose{T}(Point3{T}, r::Rectangle)` can actually return the needed vertices for a rectangle.
43
-
This together with `convert` enables us to create mesh primitives like this:
44
-
```Julia
45
-
MeshType(Cube(...))
46
-
MeshType(Sphere(...))
47
-
MeshType(Volume, 0.4f0) #0.4f0 => isovalue
48
-
```
34
+
### Usage
49
35
50
-
Similarly, I can pass a meshtype to an IO function, which then parses only the attributes that I really need.
51
-
So passing `Mesh{Point3{Float32}, Face3{UInt32}}` to the obj importer will skip normals, uv coordinates etc, and automatically converts the given attributes to the right number type.
36
+
The GeometryBasics `Mesh` supports vertex attributes with different lengths which get addressed by different faces (as of 0.5).
37
+
As such MeshIO makes no effort to convert vertex attributes to a common length, indexed by one set of faces.
38
+
If you need a single set of faces, e.g. for rendering, you can use `new_mesh = GeometryBasics.expand_faceviews(mesh)` to generate a fitting mesh.
52
39
53
-
To put this one level further, the `Face` type has the index offset relative to Julia's indexing as a parameter (e.g. `Face3{T, 0}` is 1 indexed). Also, you can index into an array with this face type, and it will convert the indexes correctly while accessing the array. So something like this always works, independent of the underlying index offset:
54
-
```Julia
55
-
v1, v2, v3 = vertices[face]
40
+
The GeometryBasics `Mesh` allows for different element types for coordinates, normals, faces, etc.
41
+
These can set when loading a mesh using keyword arguments:
Also, the importer is sensitive to this, so if you always want to work with 0-indexed faces (like it makes sense for opengl based visualizations), you can parse the mesh already as an 0-indexed mesh, by just defining the mesh format to use `Face3{T, -1}`. (only the OBJ importer yet)
45
+
Note that not every file format supports normals and uvs (texture coordinates) and thus some loaders don't accept `uvtype` and/or `normaltype`.
58
46
59
-
Small example to demonstrate the advantage for IO:
# even if the native mesh format doesn't have an array of dense points or faces, the correct ones will
64
-
# now be created, or converted:
65
-
vts =decompose(Point3{Float32}, msh) # I know ply_binary needs Point3{Float32}
66
-
fcs =decompose(Face3{Int32, -1}, msh) # And 0 indexed Int32 faces.
67
-
#write code...
68
-
end
69
-
```
47
+
The facetypes from GeometryBasics support 0 and 1-based indexing using `OffsetInteger`s.
48
+
For example `GLTriangleFace` is an alias for `NgonFace{3, OffsetInteger{-1, UInt32}}`, i.e. a face containing 3 indices offset from 1-based indexing by `-1`.
49
+
The raw data in a `GLTriangleFace` is 0-based so that it can be uploaded directly in a Graphics API.
50
+
In Julia code it gets converted back to a 1-based Int, so that it can be used as is.
51
+
52
+
### Extending MeshIO
70
53
54
+
To implement a new file format you need to add the appropriate `load()` and `save()` methods.
55
+
You also need to register the file format with [FileIO](https://juliaio.github.io/FileIO.jl/stable/registering/)
56
+
For saving it may be useful to know that you can convert vertex data to specific types using the [decompose interface](https://juliageometry.github.io/GeometryBasics.jl/stable/decomposition/).
0 commit comments