{"id":13896346,"url":"https://github.com/p3r7/3d","last_synced_at":"2025-08-16T14:32:04.344Z","repository":{"id":92559356,"uuid":"320544724","full_name":"p3r7/3d","owner":"p3r7","description":"🧊 Pure Lua 3D lib for Norns","archived":false,"fork":false,"pushed_at":"2021-05-27T12:23:05.000Z","size":177,"stargazers_count":6,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-12-09T13:53:07.975Z","etag":null,"topics":["3d","monome-norns","norns"],"latest_commit_sha":null,"homepage":"https://llllllll.co/t/3d-pure-lua-3d-lib-for-norns/39622","language":"Lua","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/p3r7.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2020-12-11T10:43:19.000Z","updated_at":"2024-08-08T04:24:27.000Z","dependencies_parsed_at":null,"dependency_job_id":"55e5fed3-df13-4062-825f-98c799559835","html_url":"https://github.com/p3r7/3d","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p3r7%2F3d","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p3r7%2F3d/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p3r7%2F3d/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p3r7%2F3d/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/p3r7","download_url":"https://codeload.github.com/p3r7/3d/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230040676,"owners_count":18163603,"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","monome-norns","norns"],"created_at":"2024-08-06T18:02:51.189Z","updated_at":"2024-12-16T23:35:31.862Z","avatar_url":"https://github.com/p3r7.png","language":"Lua","readme":"# 3d\n\nPure Lua 3D lib for norns.\n\n![teapot](https://www.eigenbahn.com/assets/gif/norns_3d_teapot.gif)\n\n\n## Description\n\nProvides classes for storing \u0026 manipulating 3D objects, with similar APIs but different internal structures:\n\n - [Polyhedron](./lib/3d/polyhedron.lua)\n - [Wireframe](./lib/3d/wireframe.lua)\n - [Sphere](./lib/3d/sphere.lua)\n\n`Polyhedron` has a notion of faces composed of vertices. It is more suited for importing 3D models.\n\n`Wireframe`, on the other hand, only has a notion of edges (line between points). It is more suited for representing models with internal edges (such as an hypercube).\n\nBoth support importing `.OBJ` models (even though `Polyhedron` is more naturally suited for this use-case).\n\n`Sphere` is just a basic sphere.\n\n\n## Usage\n\n#### Basic\n\nImporting a 3D model and displaying it.\n\n```lua\nlocal Polyhedron = include('lib/3d/polyhedron')\nlocal draw_mode = include('lib/3d/enums/draw_mode')\n\nlocal model = Polyhedron.new_from_obj(\"/home/we/dust/code/3d/model/teapot.obj\")\nlocal level = 15\nmodel:draw(level, draw_mode.FACES)\n```\n\nRotating it:\n\n```lua\nlocal axis = include('lib/3d/enums/axis')\n\nmodel:rotate(axis.Y, 0.02)\n```\n\nDrawing can take a multiplication coefficient and a camera position:\n\n```lua\nlocal mult = 64        -- scale up model by 640%\nlocal cam = {0, 0, -4} -- camera coordinates (x, y, z)\nmodel:draw(level, draw_mode.FACES, mult, cam)\n```\n\nThis is important as `.OBJ` models vary greatly in scale and are not necessarily origin-centered.\n\nSee the [teapot](./obj_teapot.lua) (`Polyhedron`) and [wireframe_cube](./wireframe_cube.lua) (`Wireframe`) examples for this basic use-case.\n\n\n#### Drawing modes\n\nSeveral draw mode are supported:\n\n```lua\nmodel:draw(nil,   draw_mode.FACES)     -- faces (not supported by `Wireframe`)\nmodel:draw(level, draw_mode.WIREFRAME) -- edges\nmodel:draw(level, draw_mode.POINTS)    -- vertices\n```\n\nAnd can be combined:\n\n```lua\nmodel:draw(level, draw_mode.FACES | draw_mode.WIREFRAME) -- faces + edges\n```\n\nIn this case, independent screen levels can be specified:\n\n```lua\nmodel:draw(level, draw_mode.WIREFRAME | draw_mode.POINTS, nil, nil,\n           {line_level = 10,\n            point_level = 5})\n```\n\nSee the [octagon](./obj_octagon.lua) example to illustrate this use-case.\n\n\n#### Custom drawing function\n\nA custom drawing function can be configured:\n\n```lua\nfunction draw_v_as_circle(x, y, l)\n  if l then\n    screen.level(l)\n  end\n  local radius = 2\n  screen.move(x + radius, y)\n  screen.circle(x, y, radius)\n  screen.fill()\nend\n\nmodel:draw(level, draw_mode.POINTS, mult, cam,\n           {point_draw_fn = draw_v_as_circle})\n```\n\nCustom drawing function parameter depends of `draw_mode`:\n\n| object \\ draw_mode | `POINTS`                 | `WIREFRAME`                        | `FACES`                    |\n| ---                | ---                      | ---                                | ---                        |\n| `Wireframe`        | `point_draw_fn(x, y, l)` | `lines_draw_fn(x0, y0, x1, y1, l)` | n/a                        |\n| `Polyhedron`       | `point_draw_fn(x, y, l)` | `face_edges_draw_fn(f_edges, l)`   | `face_draw_fn(f_edges, l)` |\n\n\nSee the [octagon](./obj_octagon.lua) example to illustrate this use-case.\n\n\n#### Conditional drawing\n\nDrawing of vertices/edges/faces can be conditional thanks to these props:\n\n| prop       | description                                            |\n| ---        | ---                                                    |\n| `draw_pct` | % of chance that element get drawn                     |\n| `min_z`    | elements w/ at least 1 vertex bellow value are skipped |\n| `maw_z`    | elements w/ at least 1 vertex above value are skipped |\n\nWhen tuned appropriately, this can lead to a nice glitchy effect.\n\nSee the [octaglitch](./obj_octaglitch.lua) example.\n\n\u003cdetails\u003e\u003csummary markdown=\"span\"\u003e\u003cb\u003e!!! EPILEPSY WARNING !!!\u003c/b\u003e\u003c/summary\u003e\n\u003cimg src=\"https://www.eigenbahn.com/assets/gif/norns_3d_glitch.gif\"/\u003e\n\u003c/details\u003e\n\n\n#### Glitchy elements\n\n`Wireframe`, when in `draw_mode.WIREFRAME`, supports drawing random lines between vertices.\n\n| prop                     | description                                      |\n| ---                      | ---                                              |\n| `glitch_edge_pct`        | % of chance that element get drawn               |\n| `glitch_edge_amount_pct` | % of total vertices that attempts getting linked |\n\nSee the [glitchpercube](./obj_glitchpercube.lua) example.\n\n\u003cdetails\u003e\u003csummary markdown=\"span\"\u003e\u003cb\u003e!!! EPILEPSY WARNING !!!\u003c/b\u003e\u003c/summary\u003e\n\u003cimg src=\"https://www.eigenbahn.com/assets/gif/norns_3d_glitchpercube.gif\"/\u003e\n\u003c/details\u003e\n\n\n## Limitations\n\nNo clean masking support, elements (faces / edges / vertices) are drawn in no specific order.\n\nBasic masking could be enabled tuning the `min_z` drawing property, even though that'll only work properly for [highly symmetrical models](https://en.wikipedia.org/wiki/Polyhedron#Symmetries).\n\nNo support for *materials*.\n\nCurrently, glitches (conditional drawing, random elements) refresh at the same rate as the element is being drawn. Ideally we should split this \"glicthing\" logic from the drawing logic for it to be less aggressive.\n\n\n## Acknowledgements\n\n90% of the 3D vertex calculation code is based on an [example](https://gist.github.com/Ivoah/477775d13e142b2c89ba) by [@Ivoah](https://github.com/Ivoah) for [PICO-8](https://www.lexaloffle.com/pico-8.php).\n\nIt has been modified to rely on a mutating state for better performance and preventing memory consumption to grow out of control (I assume GC tuning is a bit conservative on norns).\n\nLowpoly 3D fish models used in `obj_fish.lua` example by [@rkuhlf](https://rkuhlf-assets.itch.io/) ([source](https://www.cgtrader.com/free-3d-models/animals/fish/low-poly-fish-b981402c-4bac-491b-a4d8-6bc91b8e08b0)).\n","funding_links":[],"categories":["Lua"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fp3r7%2F3d","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fp3r7%2F3d","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fp3r7%2F3d/lists"}