{"id":13423430,"url":"https://github.com/fogleman/hmm","last_synced_at":"2025-04-04T18:05:55.249Z","repository":{"id":39859284,"uuid":"203701292","full_name":"fogleman/hmm","owner":"fogleman","description":"Heightmap meshing utility.","archived":false,"fork":false,"pushed_at":"2023-12-19T02:56:41.000Z","size":233,"stargazers_count":586,"open_issues_count":13,"forks_count":54,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-03-28T17:07:57.818Z","etag":null,"topics":["3d","computational-geometry","cpp","heightmap","mesh"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fogleman.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2019-08-22T02:42:36.000Z","updated_at":"2025-03-22T15:58:57.000Z","dependencies_parsed_at":"2024-02-15T21:31:57.075Z","dependency_job_id":null,"html_url":"https://github.com/fogleman/hmm","commit_stats":{"total_commits":82,"total_committers":4,"mean_commits":20.5,"dds":0.3902439024390244,"last_synced_commit":"5ea611461e9f8b40f3d97e9f10fcf0f40592030b"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fogleman%2Fhmm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fogleman%2Fhmm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fogleman%2Fhmm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fogleman%2Fhmm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fogleman","download_url":"https://codeload.github.com/fogleman/hmm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247226213,"owners_count":20904465,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["3d","computational-geometry","cpp","heightmap","mesh"],"created_at":"2024-07-31T00:00:34.377Z","updated_at":"2025-04-04T18:05:55.225Z","avatar_url":"https://github.com/fogleman.png","language":"C","readme":"# hmm\n\n`hmm` is a \u003cb\u003eh\u003c/b\u003eeight\u003cb\u003em\u003c/b\u003eap \u003cb\u003em\u003c/b\u003eeshing utility.\n\nIf you've done any 3D game development, 3D printing, or other such things,\nyou've likely wanted to convert a grayscale heightmap image into a 3D mesh. The\nnaive way is pretty simple but generates huge meshes with millions of\ntriangles. After hacking my way through various solutions over the years, I\nfinally decided I needed to write a good tool for this purpose.\n\n`hmm` is a modern implementation of a nice algorithm from the 1995 paper\n[Fast Polygonal Approximation of Terrains and Height Fields](http://mgarland.org/files/papers/scape.pdf)\nby Garland and Heckbert. The meshes produced by `hmm` satisfy the Delaunay\ncondition and can satisfy a specified maximal error or maximal number of\ntriangles or vertices. It's also very fast.\n\n![Example](https://i.imgur.com/xLGcmWS.png)\n\n### Dependencies\n\n- C++11 or higher\n- [glm](https://glm.g-truc.net/0.9.9/index.html)\n\n### Installation\n\n```bash\nbrew install glm # on macOS\nsudo apt-get install libglm-dev # on Ubuntu / Debian\n\ngit clone https://github.com/fogleman/hmm.git\ncd hmm\nmake\nmake install\n```\n\n### Usage\n\n```\nheightmap meshing utility\nusage: hmm --zscale=float [options] ... infile outfile.stl\noptions:\n  -z, --zscale           z scale relative to x \u0026 y (float)\n  -x, --zexagg           z exaggeration (float [=1])\n  -e, --error            maximum triangulation error (float [=0.001])\n  -t, --triangles        maximum number of triangles (int [=0])\n  -p, --points           maximum number of vertices (int [=0])\n  -b, --base             solid base height (float [=0])\n      --level            auto level input to full grayscale range\n      --invert           invert heightmap\n      --blur             gaussian blur sigma (int [=0])\n      --gamma            gamma curve exponent (float [=0])\n      --border-size      border size in pixels (int [=0])\n      --border-height    border z height (float [=1])\n      --normal-map       path to write normal map png (string [=])\n      --shade-path       path to write hillshade png (string [=])\n      --shade-alt        hillshade light altitude (float [=45])\n      --shade-az         hillshade light azimuth (float [=0])\n  -q, --quiet            suppress console output\n  -?, --help             print this message\n```\n\n`hmm` supports a variety of file formats like PNG, JPG, etc. for the input\nheightmap. The output is always a binary STL file. The only other required\nparameter is `-z`, which specifies how much to scale the Z axis in the output\nmesh.\n\n```bash\n$ hmm input.png output.stl -z ZSCALE\n```\n\nYou can also provide a maximal allowed error, number of triangles, or number of\nvertices. (If multiple are specified, the first one reached is used.)\n\n```bash\n$ hmm input.png output.stl -z 100 -e 0.001 -t 1000000\n```\n\n### Visual Guide\n\nClick on the image below to see examples of various command line arguments. You\ncan try these examples yourself with this heightmap: [gale.png](https://www.michaelfogleman.com/static/hmm/guide/gale.png).\n\n![Visual Guide](https://www.michaelfogleman.com/static/hmm/guide/all.png)\n\n### Z Scale\n\nThe required `-z` parameter defines the distance between a fully black pixel\nand a fully white pixel in the vertical Z axis, with units equal to one pixel\nwidth or height. For example, if each pixel in the heightmap represented a 1x1\nmeter square area, and the vertical range of the heightmap was 100 meters, then\n`-z 100` should be used.\n\n### Z Exaggeration\n\nThe `-x` parameter is simply an extra multiplier on top of the provided Z\nscale. It is provided as a convenience so you don't have to do multiplication\nin your head just to exaggerate by, e.g. 2x, since Z scales are often derived\nfrom real world data and can have strange values like 142.2378.\n\n### Max Error\n\nThe `-e` parameter defines the maximum allowed error in the output mesh, as a\npercentage of the total mesh height. For example, if `-e 0.01` is used, then no\npixel will have an error of more than 1% of the distance between a fully black\npixel and a fully white pixel. This means that for an 8-bit input image, an\nerror of `e = 1 / 256 ~= 0.0039` will ensure that no pixel has an error greater\nthan one full grayscale unit. (It may still be desirable to use a lower value\nlike `0.5 / 256`.)\n\n### Base Height\n\nWhen the `-b` option is used to create a solid mesh, it defines the height of\nthe base before the lowest part of the heightmesh appears, as a percentage of\nthe heightmap's height. For example, if `-z 100 -b 0.5` were used, then the\nfinal mesh would be about 150 units tall (if a fully white pixel exists in the\ninput).\n\n### Border\n\nA border can be added to the mesh with the `--border-size` and\n`--border-height` flags. The heightmap will be padded by `border-size` pixels\nbefore triangulating. The (pre-scaled) Z value of the border can be set with\n`border-height` which defaults to 1.\n\n### Filters\n\nA Gaussian blur can be applied with the `--blur` flag. This is particularly\nuseful for noisy images.\n\nThe heightmap can be inverted with the `--invert` flag. This is useful for\n[lithophanes](https://en.wikipedia.org/wiki/Lithophane).\n\nThe heightmap can be auto-leveled with the `--level` flag. This will stretch\nthe grayscale values to use the entire black =\u003e white range.\n\nA gamma curve can be applied to the heightmap with the `--gamma` flag. This\napplies `x = x ^ gamma` to each pixel, where `x` is in [0, 1].\n\n### Normal Maps\n\nA full resolution [normal map](https://en.wikipedia.org/wiki/Normal_mapping)\ncan be generated with the `--normal-map` argument. This will save a normal map\nas an RGB PNG to the specified path. This is useful for rendering higher\nresolution bumps and details while using a lower resolution triangle mesh.\n\n### Hillshade Images\n\nA grayscale hillshade image can be generated with the `--shade-path` argument.\nThe altitude and azimuth of the light source can be changed with the\n`--shade-alt` and `--shade-az` arguments, which default to 45 degrees in\naltitude and 0 degrees from north (up).\n\n### Performance\n\nPerformance depends a lot on the amount of detail in the heightmap, but here\nare some figures for an example heightmap of a [40x40 kilometer area centered\non Mount Everest](https://i.imgur.com/1i9djJ0.jpg). Various heightmap\nresolutions and permitted max errors are shown. Times computed on a 2018 13\"\nMacBook Pro (2.7 GHz Intel Core i7).\n\n#### Runtime in Seconds\n\n| Image Size / Error | e=0.01 | e=0.001 | e=0.0005 | e=0.0001 |\n| ---: | ---: | ---: | ---: | ---: |\n| 9490 x 9490 px (90.0 MP) | 6.535 | 13.102 | 19.394 | 58.949 |\n| 4745 x 4745 px (22.5 MP) | 1.867 |  4.903 |  8.886 | 33.327 |\n| 2373 x 2373 px  (5.6 MP) | 0.559 |  2.353 |  4.930 | 14.243 |\n| 1187 x 1187 px  (1.4 MP) | 0.168 |  1.021 |  1.961 |  3.709 |\n\n#### Number of Triangles Output\n\n| Image Size / Error | e=0.01 | e=0.001 | e=0.0005 | e=0.0001 |\n| ---: | ---: | ---: | ---: | ---: |\n| 9490 x 9490 px (90.0 MP) | 33,869 | 1,084,972 | 2,467,831 | 14,488,022 |\n| 4745 x 4745 px (22.5 MP) | 33,148 | 1,032,263 | 2,323,772 | 11,719,491 |\n| 2373 x 2373 px  (5.6 MP) | 31,724 |   935,787 | 1,979,227 |  6,561,070 |\n| 1187 x 1187 px  (1.4 MP) | 27,275 |   629,352 | 1,160,079 |  2,347,713 |\n\n### TODO\n\n- reconstruct grayscale image?\n- better error handling, especially for file I/O\n- better overflow handling - what's the largest supported heightmap?\n- mesh validation?\n","funding_links":[],"categories":["C","C++","Maths"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffogleman%2Fhmm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffogleman%2Fhmm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffogleman%2Fhmm/lists"}