MeshIO.jl
MeshIO.jl copied to clipboard
Add experimental support for materials in wavefront obj files
This adds a couple of things:
- the main
load("filename.obj")
now also reads "usemtl" commands and treats them like a vertex attribute. I.e. it maps the related material names to indices and generates faces for them so that a mesh can later be split into submeshes based on materials -
MeshIO.split_mesh(mesh)
does the splitting based on material indices. It's not exported as I see it as an experimental feature. It's hard-coded to assume a mesh has normals, uvs and material ids for now. It returns a Dict mapping material ids to sub meshes. -
MeshIO.load_materials("filename.obj")
repeats some of the work of the main load function to provide amaterial id => material name
mapping and also loads the attached mtl file viaMeshIO._load_mtl("filename.mtl")
. I consider those experimental as well so they're not exported. The output is a nested Dict of the information in the mtl file.
For example you can use this to load https://free3d.com/3d-model/girl-blind-703979.html. (This isn't using all the material settings specified in the mtl file so the shading doesn't match exactly. )
using FileIO, MeshIO, GeometryBasics
path = "D:/data/Julia/"
filepath = joinpath(path, "14-girl-obj/girl OBJ.obj")
mesh = load(filepath)
meshes = MeshIO.split_mesh(mesh)
materials = MeshIO.load_materials(filepath)
# filename incorrect in mtl file...?
materials["FACE"]["diffuse map"]["filename"] = "D:/data/Julia/14-girl-obj/tEXTURE/FACE Base Color apha.png"
using GLMakie
begin
fig = Figure()
ax = LScene(fig[1, 1])
for (id, m) in meshes
# get material associated with a submesh
material_name = materials["id to material"][id]
material = materials[material_name]
# load texture from filename specified in .mtl file
texture = if haskey(material, "diffuse map") && haskey(material["diffuse map"], "filename")
load(material["diffuse map"]["filename"])
else
RGBf(0,1,0)
end
# texture uses white as transparent for some reason...
if material_name == "FACE"
texture = map(texture) do c
RGBAf(c.r, c.g, c.b, 1 - c.r)
end
end
# render mesh with specified material properties if specified
mesh!(ax, m, color = texture,
diffuse = get(material, "diffuse", Vec3f(1)),
specular = get(material, "specular", Vec3f(0.2)),
shininess = get(material, "shininess", 32f0),
)
end
fig
end