• Stars
    star
    568
  • Rank 78,483 (Top 2 %)
  • Language
    C
  • License
    MIT License
  • Created about 5 years ago
  • Updated 11 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Heightmap meshing utility.

hmm

hmm is a heightmap meshing utility.

If you've done any 3D game development, 3D printing, or other such things, you've likely wanted to convert a grayscale heightmap image into a 3D mesh. The naive way is pretty simple but generates huge meshes with millions of triangles. After hacking my way through various solutions over the years, I finally decided I needed to write a good tool for this purpose.

hmm is a modern implementation of a nice algorithm from the 1995 paper Fast Polygonal Approximation of Terrains and Height Fields by Garland and Heckbert. The meshes produced by hmm satisfy the Delaunay condition and can satisfy a specified maximal error or maximal number of triangles or vertices. It's also very fast.

Example

Dependencies

  • C++11 or higher
  • glm

Installation

brew install glm # on macOS
sudo apt-get install libglm-dev # on Ubuntu / Debian

git clone https://github.com/fogleman/hmm.git
cd hmm
make
make install

Usage

heightmap meshing utility
usage: hmm --zscale=float [options] ... infile outfile.stl
options:
  -z, --zscale           z scale relative to x & y (float)
  -x, --zexagg           z exaggeration (float [=1])
  -e, --error            maximum triangulation error (float [=0.001])
  -t, --triangles        maximum number of triangles (int [=0])
  -p, --points           maximum number of vertices (int [=0])
  -b, --base             solid base height (float [=0])
      --level            auto level input to full grayscale range
      --invert           invert heightmap
      --blur             gaussian blur sigma (int [=0])
      --gamma            gamma curve exponent (float [=0])
      --border-size      border size in pixels (int [=0])
      --border-height    border z height (float [=1])
      --normal-map       path to write normal map png (string [=])
      --shade-path       path to write hillshade png (string [=])
      --shade-alt        hillshade light altitude (float [=45])
      --shade-az         hillshade light azimuth (float [=0])
  -q, --quiet            suppress console output
  -?, --help             print this message

hmm supports a variety of file formats like PNG, JPG, etc. for the input heightmap. The output is always a binary STL file. The only other required parameter is -z, which specifies how much to scale the Z axis in the output mesh.

$ hmm input.png output.stl -z ZSCALE

You can also provide a maximal allowed error, number of triangles, or number of vertices. (If multiple are specified, the first one reached is used.)

$ hmm input.png output.stl -z 100 -e 0.001 -t 1000000

Visual Guide

Click on the image below to see examples of various command line arguments. You can try these examples yourself with this heightmap: gale.png.

Visual Guide

Z Scale

The required -z parameter defines the distance between a fully black pixel and a fully white pixel in the vertical Z axis, with units equal to one pixel width or height. For example, if each pixel in the heightmap represented a 1x1 meter square area, and the vertical range of the heightmap was 100 meters, then -z 100 should be used.

Z Exaggeration

The -x parameter is simply an extra multiplier on top of the provided Z scale. It is provided as a convenience so you don't have to do multiplication in your head just to exaggerate by, e.g. 2x, since Z scales are often derived from real world data and can have strange values like 142.2378.

Max Error

The -e parameter defines the maximum allowed error in the output mesh, as a percentage of the total mesh height. For example, if -e 0.01 is used, then no pixel will have an error of more than 1% of the distance between a fully black pixel and a fully white pixel. This means that for an 8-bit input image, an error of e = 1 / 256 ~= 0.0039 will ensure that no pixel has an error greater than one full grayscale unit. (It may still be desirable to use a lower value like 0.5 / 256.)

Base Height

When the -b option is used to create a solid mesh, it defines the height of the base before the lowest part of the heightmesh appears, as a percentage of the heightmap's height. For example, if -z 100 -b 0.5 were used, then the final mesh would be about 150 units tall (if a fully white pixel exists in the input).

Border

A border can be added to the mesh with the --border-size and --border-height flags. The heightmap will be padded by border-size pixels before triangulating. The (pre-scaled) Z value of the border can be set with border-height which defaults to 1.

Filters

A Gaussian blur can be applied with the --blur flag. This is particularly useful for noisy images.

The heightmap can be inverted with the --invert flag. This is useful for lithophanes.

The heightmap can be auto-leveled with the --level flag. This will stretch the grayscale values to use the entire black => white range.

A gamma curve can be applied to the heightmap with the --gamma flag. This applies x = x ^ gamma to each pixel, where x is in [0, 1].

Normal Maps

A full resolution normal map can be generated with the --normal-map argument. This will save a normal map as an RGB PNG to the specified path. This is useful for rendering higher resolution bumps and details while using a lower resolution triangle mesh.

Hillshade Images

A grayscale hillshade image can be generated with the --shade-path argument. The altitude and azimuth of the light source can be changed with the --shade-alt and --shade-az arguments, which default to 45 degrees in altitude and 0 degrees from north (up).

Performance

Performance depends a lot on the amount of detail in the heightmap, but here are some figures for an example heightmap of a 40x40 kilometer area centered on Mount Everest. Various heightmap resolutions and permitted max errors are shown. Times computed on a 2018 13" MacBook Pro (2.7 GHz Intel Core i7).

Runtime in Seconds

Image Size / Error e=0.01 e=0.001 e=0.0005 e=0.0001
9490 x 9490 px (90.0 MP) 6.535 13.102 19.394 58.949
4745 x 4745 px (22.5 MP) 1.867 4.903 8.886 33.327
2373 x 2373 px (5.6 MP) 0.559 2.353 4.930 14.243
1187 x 1187 px (1.4 MP) 0.168 1.021 1.961 3.709

Number of Triangles Output

Image Size / Error e=0.01 e=0.001 e=0.0005 e=0.0001
9490 x 9490 px (90.0 MP) 33,869 1,084,972 2,467,831 14,488,022
4745 x 4745 px (22.5 MP) 33,148 1,032,263 2,323,772 11,719,491
2373 x 2373 px (5.6 MP) 31,724 935,787 1,979,227 6,561,070
1187 x 1187 px (1.4 MP) 27,275 629,352 1,160,079 2,347,713

TODO

  • reconstruct grayscale image?
  • better error handling, especially for file I/O
  • better overflow handling - what's the largest supported heightmap?
  • mesh validation?

More Repositories

1

primitive

Reproducing images with geometric primitives.
Go
12,639
star
2

Craft

A simple Minecraft clone written in C using modern OpenGL (shaders).
C
10,374
star
3

nes

NES emulator written in Go.
Go
5,427
star
4

Minecraft

Simple Minecraft-inspired program using Python and Pyglet
Python
5,220
star
5

gg

Go Graphics - 2D rendering in Go with a simple API.
Go
4,372
star
6

ln

3D line art engine.
Go
3,269
star
7

pt

A path tracer written in Go.
Go
2,077
star
8

sdf

Simple SDF mesh generation in Python
Python
1,583
star
9

Quads

Computer art based on quadtrees.
Python
1,176
star
10

fauxgl

Software-only 3D renderer written in Go.
Go
864
star
11

physarum

Physarum polycephalum slime mold simulation
Go
857
star
12

Tiling

Tilings of regular polygons.
Python
482
star
13

rbgg

Isolate and remove the background gradient from images of paper.
Go
360
star
14

pack3d

Tightly pack 3D models.
Go
323
star
15

rush

Rush Hour puzzle goodies!
Go
287
star
16

axi

Library for working with the AxiDraw v3 pen plotter.
Python
274
star
17

PirateMap

Procedurally generate pirate treasure maps.
Python
263
star
18

simplify

3D mesh simplification in Go.
Go
247
star
19

ribbon

Ribbon diagrams of proteins in #golang.
Go
243
star
20

Punchcard

Generate GitHub-style punchcard charts with ease.
Python
240
star
21

terrarium

Some code for generating topographic contour maps.
Go
222
star
22

pg

Python OpenGL Graphics Framework
Python
209
star
23

dlaf

Diffusion-limited aggregation, fast.
C++
187
star
24

FeedNotifier

Feed Notifier is a Windows application that resides in the system tray and displays pop-up notifications on your desktop when new items arrive in your subscribed RSS or Atom feeds
Python
165
star
25

CellularForms

An implementation of Andy Lomas' Cellular Forms.
C++
155
star
26

MisterQueen

A chess engine written in C.
C
148
star
27

density

Render millions of points on a map.
Go
147
star
28

meshview

Performant 3D mesh viewer written in Go.
Go
133
star
29

delaunay

Fast Delaunay triangulation implemented in Go.
Go
115
star
30

GraphLayout

Graph drawing using simulated annealing for layout.
Python
114
star
31

Piet

Procedurally Generating Images in the Style of Piet Mondrian
Python
97
star
32

ease

Easing functions in #golang.
Go
92
star
33

AdventOfCode2018

My solutions to the Advent of Code 2018 problems.
Python
81
star
34

iMeme

iMeme is a popular meme generator for Mac OS X
Objective-C
72
star
35

DCPU-16

Python scripts for DCPU-16 emulation.
DCPU-16 ASM
70
star
36

xy

Various utilities for the Makeblock XY Plotter Robot Kit
Python
70
star
37

contourmap

Compute contour lines (isolines) for any 2D data in Go.
Go
69
star
38

demsphere

Generate 3D meshes of planets, moons, etc. from spherical DEMs. (WIP)
Go
66
star
39

GPS

Real-time GPS Satellite Positions in 3D
Python
65
star
40

slicer

Fast 3D mesh slicer written in Go.
Go
61
star
41

AllRGB

Scripts for creating AllRGB images.
Python
61
star
42

pixsort

Applying the traveling salesman problem to pixel art.
Go
59
star
43

mol

Render ball-and-stick models of molecules.
Go
58
star
44

Ricochet

Implementation of Ricochet Robot (Rasende Roboter) including a GUI and a solver
Python
54
star
45

domaincoloring

Domain coloring in Go.
Go
50
star
46

Scale

Beautiful Fractals for Mac OS X.
Objective-C
40
star
47

HelloFlask

A boiler-plate starting point for a Flask web application, including SQLAlchemy, WTForms and Bootstrap.
CSS
38
star
48

gorgb

Program to create "allRGB" images.
Go
38
star
49

Field

Creating computer art by simulating charged particle field lines.
Python
37
star
50

TWL06

Official Scrabble dictionary packaged into a convenient Python module.
Python
36
star
51

serve

Simple Go file server for command line development use, a la Python's SimpleHTTPServer.
Go
34
star
52

choppy

Chop 3D models in half with a user-defined slice plane.
Go
34
star
53

Sync

Code inspired by the book.
Python
31
star
54

tracer

Global illumination path tracer in C++
C++
30
star
55

maps

Work in progress. Render maps in #golang with a simple API.
Go
27
star
56

FutureBlocks

Tetris clone written in QBasic.
Visual Basic
26
star
57

HiRISE

Convert HiRISE PDS IMG files to 3D meshes with normal maps.
Python
25
star
58

AdventOfCode2019

My solutions for Advent of Code 2019.
Python
25
star
59

AdventOfCode2021

My solutions for Advent of Code 2021.
Python
24
star
60

lissaknot

Create 3D models of Lissajous knots.
Go
24
star
61

LoginServer

Online multiplayer game login server for secure user authentication.
Python
24
star
62

pyMeme

Cross-platform meme generator application.
Python
23
star
63

HelloGL

Basic project structure for an OpenGL application.
C
22
star
64

ShortUrl

Python module for generating tiny URLs.
Python
22
star
65

imview

Simple image viewer written in Go + OpenGL.
Go
21
star
66

AdventOfCode2020

My solutions for Advent of Code 2020
Python
20
star
67

PieSlice

Making simple wallpapers out of quarter circles.
Python
20
star
68

Manhattan

Rendering the buildings of Manhattan using OSM data and NYC shapefiles.
Python
20
star
69

GameFrame

Game Frame Simulator
Objective-C
19
star
70

Phrases

Source code for a simple website that generates random, two-word phrases.
HTML
18
star
71

poissondisc

Poisson Disc sampling in Go.
Go
16
star
72

Mazes

Maze generation and rendering using Python.
Python
16
star
73

SwtPacMan

Pac-Man clone written in 2005 using Java + SWT.
Java
16
star
74

Mapper

Web app for quickly plotting markers, polylines, polygons, heatmaps, etc. on a map.
JavaScript
15
star
75

mc

Marching cubes algorithm implemented in #golang.
Go
12
star
76

Poker

Python poker hand evaluator
Python
12
star
77

GrayScott

Simple Gray Scott Reaction Diffusion model implemented in C++ and OpenCL
C++
12
star
78

WangTiling

Weighted Wang tiling.
Python
12
star
79

thumbs

Go binary that watches a folder for images and generates thumbnails of them.
Go
11
star
80

DrMario

Dr Mario clone in Python and wxPython, including AI
Python
10
star
81

Fireflies

Synchronizing fireflies using JavaScript and D3.
10
star
82

go-airspy

Go wrapper for the libairspy library.
Go
10
star
83

MLX90640

Arduino & Python code to interface with the MLX90640 thermal camera
Python
10
star
84

go-embree

Simple golang wrapper for embree using cgo
C++
9
star
85

triangulate

Polygon triangulation via ear clipping in #golang.
Go
8
star
86

wxSnow

Falling snowflakes on your Windows desktop.
Python
8
star
87

WellPlate

Python + wxPython user interface for 96 and 384 well plates.
Python
8
star
88

platformer

It's happening!
Go
8
star
89

AdventOfCode2022

My solutions for Advent of Code 2022.
Python
8
star
90

AdventOfCode2023

My solutions to the Advent of Code 2023 puzzles.
Python
7
star
91

Yellow

Visualization for 2015 NYC Yellow Taxi Trips
JavaScript
7
star
92

motion

Constant acceleration motion planner written in Go.
Go
7
star
93

Turing

2-D Turing Machine
Python
7
star
94

Boggle

Web-based Boggle clone written using Python and Flask
Python
6
star
95

colormap

Colormaps for Go.
Go
6
star
96

go-maps

Utilities for rendering maps in Go.
Go
6
star
97

slices2stl

Go
6
star
98

CurveMesh

Python
6
star
99

StarRocket

Star Rocket is a cartoon-themed space game with over 120 action-packed levels!
Objective-C
6
star
100

visvalingam

Visvalingam-Whyatt line simplification algorithm in Go.
Go
6
star