Skip to content

Commit

Permalink
Merge 9c28d8f into 9363b6e
Browse files Browse the repository at this point in the history
  • Loading branch information
mikedh committed Jul 3, 2019
2 parents 9363b6e + 9c28d8f commit db680bb
Show file tree
Hide file tree
Showing 84 changed files with 8,478 additions and 2,547 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Expand Up @@ -98,6 +98,9 @@ venv.bak/
.spyderproject
.spyproject

# vscode project settings
.vscode

# Rope project settings
.ropeproject

Expand Down
19 changes: 8 additions & 11 deletions .travis.yml
Expand Up @@ -86,24 +86,21 @@ install:
- pip install -U autopep8 flake8

script:
# style check
# style checks
- flake8 trimesh/
- flake8 example/
- flake8 tests/
# will error on non-pep8 formatting
- autopep8 --recursive --aggressive --diff --exit-code trimesh/
- autopep8 --recursive --aggressive --diff --exit-code examples/
- autopep8 --recursive --aggressive --diff --exit-code tests/

# try simple tests with only minimal deps
# try simple tests with only minimal install (just numpy)
- python -c "import trimesh"
- pytest -p no:warnings tests/test_inertia.py

# shapely/rtree are easiest to get from conda
# in Python 3.4 conda tries to downgrade Python to 2.7
- conda install -q scikit-image;

# pyembree and python-fcl not available everywhere
- if [[ "$PYTHON_VERSION" == "3.6" ]]; then conda install pyembree; fi;
# pyembree, scikit-image, python-fcl not available everywhere
- if [[ "$PYTHON_VERSION" == "3.6" ]]; then conda install pyembree scikit-image; fi;
- if [[ "$PYTHON_VERSION" == "3.6" ]]; then pip install python-fcl; fi;

# install most deps here
Expand All @@ -123,12 +120,12 @@ script:
# downgrade networkx from 2.x to 1.x to make sure our
# graph operations work on both versions of their API
- pip install -q -Iv networkx==1.11
# print version for logs
- python -c "import networkx; print('::NX_VERSION::', networkx.__version__)"
# fail if it didn't install old networkx for some reason
- python -c "import networkx; assert networkx.__version__ == '1.11')"
# will print tons of depreciation warnings we don't care about
- pytest -p no:warnings tests/test_graph.py tests/test_scene.py

# make sure examples still work
# make sure examples still work by running them all
- cd examples
- set -xe; for f in *py*; do python ../tests/notebooks.py ci exec "$f"; done
- cd ..
Expand Down
35 changes: 25 additions & 10 deletions README.md
Expand Up @@ -14,29 +14,22 @@ Pull requests are appreciated and responded to promptly! If you'd like to contri

## Basic Installation

The minimal requirements to import trimesh are
[numpy](http://www.numpy.org/), [scipy](http://www.scipy.org) and [networkx](https://networkx.github.io). Installing other packages mentioned adds functionality but is **not required**.

For the easiest install with *only* these minimal dependencies `pip` can generally install `trimesh` cleanly on Windows, Linux, and OSX:
Keeping `trimesh` easy to install is a core goal, thus the *only* hard dependancy is [numpy](http://www.numpy.org/). Installing other packages adds functionality but is not required. For the easiest install with just numpy, `pip` can generally install `trimesh` cleanly on Windows, Linux, and OSX:

```bash
pip install trimesh
```

For more functionality, like faster ray queries (`pyembree`), vector path handling (`shapely` and `rtree`), preview windows (`pyglet`), faster cache checks (`xxhash`) and more, the easiest way to get a full `trimesh` install is a [conda environment](https://conda.io/miniconda.html):
For more functionality, like convex hulls (`scipy`), graph operations (`networkx`), faster ray queries (`pyembree`), vector path handling (`shapely` and `rtree`), preview windows (`pyglet`), faster cache checks (`xxhash`) and more, the easiest way to get a full `trimesh` install is a [conda environment](https://conda.io/miniconda.html):

```bash
# this will install all soft dependencies available on your current platform
conda install -c conda-forge trimesh
```

If you're feeling lucky, you can try:
To install `trimesh` with all the soft dependancies which install cleanly on Windows, Linux, and OSX using `pip`:
```bash
# will try to install things that aren't too tricky
pip install trimesh[easy]

# will try to install everything
pip install trimesh[all]
```

Further information is available in the [advanced installation documentation](https://trimsh.org/install.html).
Expand Down Expand Up @@ -177,6 +170,28 @@ Trimesh includes an optional `pyglet` based viewer for debugging and inspecting.

If called from inside a `jupyter` notebook, `mesh.show()` displays an in-line preview using `three.js` to display the mesh or scene. For more complete rendering (PBR, better lighting, shaders, better off-screen support, etc) [pyrender](https://github.com/mmatl/pyrender) is designed to interoperate with `trimesh` objects.

## Projects Using Trimesh

You can check out the [Github network](https://github.com/mikedh/trimesh/network/dependents) for things using trimesh. A select few:

- [pyrender](https://github.com/mmatl/pyrender) Render scenes using nice looking PBR materials
- [urdfpy](https://github.com/mmatl/urdfpy) Load URDF robot descriptions
- [vtkplotter](https://github.com/marcomusy/vtkplotter) Visualize meshes interactively
- [fsleyes](https://users.fmrib.ox.ac.uk/~paulmc/fsleyes/userdoc/latest/quick_start.html) View MRI images and brain data

## Which Mesh Format Should I Use?

Quick recommendation: `GLB`, `PLY`, or `STL`. If you can, avoid `OBJ`.

There are a lot of mesh formats out there and you are usually constrained by the other software in your pipeline. If you have a choice of formats, binary `PLY` is a great option. It has a header format which is [sensible and easy to parse](http://paulbourke.net/dataformats/ply/), followed by a compact binary blob.

If you'd like something more powerful, including instancing, colors, textures, and more, `GLB` is a terrific choice. GLTF/GLB is an [extremely well specified](https://github.com/KhronosGroup/glTF/tree/master/specification/2.0) modern format that is easy and fast to parse: it has a JSON header describing data in a binary blob. It has a simple hierarchical scene graph, a great looking modern physically based material system, support in [dozens-to-hundreds of libraries](https://github.com/KhronosGroup/glTF/issues/1058), and a [John Carmack endorsment](https://www.khronos.org/news/press/significant-gltf-momentum-for-efficient-transmission-of-3d-scenes-models).

In the wild, `STL` is perhaps the most common format. `STL` files are extremely simple: it is basically just a list of triangles. They are very robust and an excellent choice for basic geometry.

If texture or color is required Wavefront `OBJ` is often used. Unfortunately OBJ doesn't have a specification so every importer and exporter implements things slightly differently, making it tough to support. It also allows unfortunate things like arbitrary sized polygons, has a face representation which is easy to mess up, references other files for materials and textures, arbitrarily interleaves data, and is slow to parse. Give `GLB` or `PLY` a try as an alternative!


## Containers

If you want to deploy something in a container that uses trimesh, automated builds containing trimesh and its dependencies are available on Docker Hub:
Expand Down
2 changes: 1 addition & 1 deletion docker/builds/apt.bash
@@ -1,6 +1,6 @@
set -xe
apt-get update
apt-get install -y --no-install-recommends blender openscad wget bzip2 supervisor libgl1-mesa-glx libgl1-mesa-dri xvfb xauth libgeos-dev libspatialindex-c4v5 libassimp-dev ca-certificates
apt-get install -y --no-install-recommends blender openscad wget bzip2 supervisor libgl1-mesa-glx libgl1-mesa-dri xvfb xauth libgeos-dev libspatialindex-c4v5 libassimp-dev ca-certificates zstd

# remove garbage
apt-get clean
Expand Down
12 changes: 12 additions & 0 deletions docker/builds/binvox.bash
@@ -0,0 +1,12 @@
# exit if any line fails
set -xe
# grab the binvox binary from the trimesh S3 bucket
# do this to avoid CI hammering the original address:
# http://www.patrickmin.com/binvox/linux64/binvox
wget https://trimesh.s3-us-west-1.amazonaws.com/binvox
# check the hash of the file before using it
echo "cc05b3ceec0b3f7061f629448c3764e87f035ec34bba46ec4dcc21e089dd40c5 binvox" | sha256sum --check
# make it executable
chmod +x binvox
# move binary to path
mv binvox /usr/bin/
6 changes: 1 addition & 5 deletions docker/builds/conda.bash
Expand Up @@ -7,6 +7,7 @@ wget https://repo.anaconda.com/miniconda/Miniconda3-4.5.4-Linux-x86_64.sh --quie
echo "80ecc86f8c2f131c5170e43df489514f80e3971dd105c075935470bbf2476dea miniconda.sh" | sha256sum --check
# run miniconda install
bash miniconda.sh -b -p ~/conda
# delete installer
rm miniconda.sh

# make sure conda bin is in front of PATH so we get correct pip
Expand All @@ -15,11 +16,6 @@ export PATH="~/conda/bin:$PATH"
# create a conda env
conda config --set always_yes yes --set changeps1 no
conda create -q -n denv python=3.6

# make sure pip/conda is the latest
pip install --upgrade pip
conda update -n base conda

# add conda-forge as remote channel
conda config --add channels conda-forge

Expand Down
2 changes: 2 additions & 0 deletions docker/builds/vhacd.bash
@@ -1,5 +1,7 @@
set -xe

# remove any copies
rm -f testVHACD
# grab the VHACD (convex segmenter) binary
wget https://github.com/mikedh/v-hacd-1/raw/master/bin/linux/testVHACD
# check the hash of the downloaded file
Expand Down
116 changes: 116 additions & 0 deletions examples/voxel.py
@@ -0,0 +1,116 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import os
import numpy as np
import inspect
import trimesh
from trimesh.exchange.binvox import voxelize_mesh
from trimesh import voxel as v


dir_current = os.path.dirname(
os.path.abspath(
inspect.getfile(
inspect.currentframe())))
# the absolute path for our reference models
dir_models = os.path.abspath(
os.path.join(dir_current, '..', 'models'))


def show(chair_mesh, chair_voxels, colors=(1, 1, 1, 0.3)):
scene = chair_mesh.scene()
scene.add_geometry(chair_voxels.as_boxes(colors=colors))
scene.show()


base_name = 'chair_model'
chair_mesh = trimesh.load(os.path.join(dir_models, '%s.obj' % base_name))
if isinstance(chair_mesh, trimesh.scene.Scene):
chair_mesh = trimesh.util.concatenate([
trimesh.Trimesh(mesh.vertices, mesh.faces)
for mesh in chair_mesh.geometry.values()])

binvox_path = os.path.join(dir_models, '%s.binvox' % base_name)
chair_voxels = trimesh.load(binvox_path)

chair_voxels = v.VoxelGrid(chair_voxels.encoding.dense, chair_voxels.transform)

print('white: voxelized chair (binvox, exact)')
show(
chair_mesh,
voxelize_mesh(chair_mesh, exact=True),
colors=(1, 1, 1, 0.3))

print('red: binvox-loaded chair')
show(chair_mesh, chair_voxels, colors=(1, 0, 0, 0.3))

voxelized_chair_mesh = chair_mesh.voxelized(np.max(chair_mesh.extents) / 32)
print('green: voxelized chair (default).')
show(chair_mesh, voxelized_chair_mesh, colors=(0, 1, 0, 0.3))

shape = (50, 17, 63)
revox = chair_voxels.revoxelized(shape)
print('cyan: revoxelized.')
show(chair_mesh, revox, colors=(0, 1, 1, 0.3))

values = chair_voxels.encoding.dense.copy()
values[:values.shape[0] // 2] = 0
stripped = v.VoxelGrid(values, chair_voxels.transform.copy()).strip()
print('yellow: stripped halved voxel grid. Transform is updated appropriately')
show(chair_mesh, stripped, colors=(1, 1, 0, 0.3))

transform = np.eye(4)
transform[:3] += np.random.normal(size=(3, 4)) * 0.2
transformed_chair_mesh = chair_mesh.copy().apply_transform(transform)
print('original transform volume: %s'
% str(chair_voxels.element_volume))

chair_voxels.apply_transform(transform)
print('warped transform volume: %s' % str(chair_voxels.element_volume))
print('blue: transformed voxels. Transformation is lazy, and each voxel is '
'no longer a cube.')
show(transformed_chair_mesh, chair_voxels, colors=(0, 0, 1, 0.3))


voxelized = chair_mesh.voxelized(pitch=0.02, method='subdivide').fill()
print('green: subdivided')
show(chair_mesh, voxelized, colors=(0, 1, 0, 0.3))

voxelized = chair_mesh.voxelized(pitch=0.02, method='ray')
print('red: ray. Poor performance on thin structures')
show(chair_mesh, voxelized, colors=(1, 0, 0, 0.3))

voxelized = chair_mesh.voxelized(pitch=0.02, method='binvox')
print('red: binvox (default). Poor performance on thin structures')
show(chair_mesh, voxelized, colors=(1, 0, 0, 0.3))

voxelized = chair_mesh.voxelized(pitch=0.02, method='binvox', wireframe=True)
print('green: binvox (wireframe). Still doesn\'t capture all thin structures')
show(chair_mesh, voxelized, colors=(0, 1, 0, 0.3))

voxelized = chair_mesh.voxelized(pitch=0.02, method='binvox', exact=True)
print('blue: binvox (exact). Does a good job')
show(chair_mesh, voxelized, colors=(0, 0, 1, 0.3))

voxelized = chair_mesh.voxelized(
pitch=0.02,
method='binvox',
exact=True,
downsample_factor=2,
downsample_threshold=1,
)
print('red: binvox (exact downsampled) surface')
show(chair_mesh, voxelized, colors=(1, 0, 0, 0.3))

chair_voxels = chair_mesh.voxelized(pitch=0.02, method='binvox', exact=True)

voxelized = chair_voxels.copy().fill(method='base')
print('blue: binvox (exact) filled (base). Gets a bit overly excited')
show(chair_mesh, voxelized, colors=(0, 0, 1, 0.3))

voxelized = chair_voxels.copy().fill(method='orthographic')
print('green: binvox (exact) filled (orthographic). '
'Doesn\'t do much as should be expected')
show(chair_mesh, voxelized, colors=(0, 1, 0, 0.3))
30 changes: 30 additions & 0 deletions examples/voxel_fillers.py
@@ -0,0 +1,30 @@
from trimesh.scene import Scene
from trimesh.primitives import Sphere
from trimesh.voxel.morphology import fillers

mesh = Sphere()


def show(surface, filled, label):
print(label)
scene = Scene()
scene.add_geometry(surface.as_boxes(colors=(1, 0, 0, 0.3)))
scene.add_geometry(filled.as_boxes(colors=(0, 0, 1, 0.5)))
scene.show()


# remove_internal produced unexpected results when boundary pixels are occupied
# not useful very often, but handy to demonstrate filling algorithms.
surface = mesh.voxelized(
pitch=0.2, method='binvox', remove_internal=True)
for impl in fillers:
show(surface, surface.copy().fill(method=impl), impl)


filled = mesh.voxelized(
pitch=0.05, method='binvox', exact=True).fill(method='holes')
hollow = filled.copy().hollow()
print('filled volume, hollow_volume')
print(filled.volume, hollow.volume)
print('hollow voxel (zoom in to see hollowness)')
hollow.show()
Binary file added models/chair_model.binvox
Binary file not shown.
9 changes: 9 additions & 0 deletions models/rabbit.mtl
@@ -0,0 +1,9 @@
# Exported from Wings 3D 0.98.29b
newmtl default
Ns 100.000
d 1.00000
illum 2
Kd 1.00000 0.00000 1.00000
Ka 1.00000 0.00000 1.00000
Ks 1.00000 0.00000 1.00000
Ke 0.00000e+0 0.00000e+0 0.00000e+0

0 comments on commit db680bb

Please sign in to comment.