{"id":13413203,"url":"https://github.com/fogleman/ln","last_synced_at":"2025-04-14T06:53:38.095Z","repository":{"id":46098782,"uuid":"49353330","full_name":"fogleman/ln","owner":"fogleman","description":"3D line art engine.","archived":false,"fork":false,"pushed_at":"2019-07-19T09:00:40.000Z","size":77,"stargazers_count":3261,"open_issues_count":12,"forks_count":131,"subscribers_count":89,"default_branch":"master","last_synced_at":"2024-07-31T20:52:00.985Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://godoc.org/github.com/fogleman/ln/ln","language":"Go","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}},"created_at":"2016-01-10T04:28:10.000Z","updated_at":"2024-07-22T17:34:31.000Z","dependencies_parsed_at":"2022-09-02T04:20:13.411Z","dependency_job_id":null,"html_url":"https://github.com/fogleman/ln","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/fogleman%2Fln","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fogleman%2Fln/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fogleman%2Fln/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fogleman%2Fln/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fogleman","download_url":"https://codeload.github.com/fogleman/ln/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248837281,"owners_count":21169374,"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":[],"created_at":"2024-07-30T20:01:35.080Z","updated_at":"2025-04-14T06:53:38.072Z","avatar_url":"https://github.com/fogleman.png","language":"Go","readme":"# `ln` The 3D Line Art Engine\n\n`ln` is a vector-based 3D renderer written in Go. It is used to produce 2D\nvector graphics (think SVGs) depicting 3D scenes.\n\n*The output of an OpenGL pipeline is a rastered image. The output of `ln` is\na set of 2D vector paths.*\n\n![Examples](http://i.imgur.com/HY2Fg2t.png)\n\n## Motivation\n\nI created this so I could plot 3D drawings with my\n[Makeblock XY Plotter](http://www.makeblock.cc/xy-plotter-robot-kit/).\n\nHere's one of my drawings from the plotter...\n\n![Example](http://i.imgur.com/NbgpUhQ.jpg)\n\n## Installation\n\n\tgo get github.com/fogleman/ln/ln\n\n## Features\n\n- Primitives\n\t- Sphere\n\t- Cube\n\t- Triangle\n\t- Cylinder\n\t- 3D Functions\n- Triangle Meshes\n\t- OBJ \u0026 STL\n- Vector-based \"Texturing\"\n- CSG (Constructive Solid Geometry) Operations\n\t- Intersection\n\t- Difference\n\t- Union\n- Output to PNG or SVG\n\n## How it Works\n\nTo understand how `ln` works, it's useful to start with the `Shape` interface:\n\n```go\ntype Shape interface {\n\tPaths() Paths\n\tIntersect(Ray) Hit\n\tContains(Vector, float64) bool\n\tBoundingBox() Box\n\tCompile()\n}\n```\n\nEach shape must provide some `Paths` which are 3D polylines on the surface\nof the solid. Ultimately anything drawn in the final image is based on these\npaths. These paths can be anything. For a sphere they could be lat/lng grid\nlines, a triangulated-looking surface, dots on the surface, etc. This is what\nwe call vector-based texturing. Each built-in `Shape` ships with a default\n`Paths` function (e.g. a `Cube` simply draws the outline of a cube) but you\ncan easily provide your own.\n\nEach shape must also provide an `Intersect` method that lets the engine test\nfor ray-solid intersection. This is how the engine knows what is visible to the\ncamera and what is hidden.\n\nAll of the `Paths` are chopped up to some granularity and each point is tested\nby shooting a ray toward the camera. If there is no intersection, that point is\nvisible. If there is an intersection, it is hidden and will not be rendered.\n\nThe visible points are then transformed into 2D space using transformation\nmatrices. The result can then be rendered as PNG or SVG.\n\nThe `Contains` method is only needed for CSG (Constructive Solid Geometry)\noperations.\n\n## Hello World: A Single Cube\n\n### The Code\n\n```go\npackage main\n\nimport \"github.com/fogleman/ln/ln\"\n\nfunc main() {\n\t// create a scene and add a single cube\n\tscene := ln.Scene{}\n\tscene.Add(ln.NewCube(ln.Vector{-1, -1, -1}, ln.Vector{1, 1, 1}))\n\n\t// define camera parameters\n\teye := ln.Vector{4, 3, 2}    // camera position\n\tcenter := ln.Vector{0, 0, 0} // camera looks at\n\tup := ln.Vector{0, 0, 1}     // up direction\n\n\t// define rendering parameters\n\twidth := 1024.0  // rendered width\n\theight := 1024.0 // rendered height\n\tfovy := 50.0     // vertical field of view, degrees\n\tznear := 0.1     // near z plane\n\tzfar := 10.0     // far z plane\n\tstep := 0.01     // how finely to chop the paths for visibility testing\n\n\t// compute 2D paths that depict the 3D scene\n\tpaths := scene.Render(eye, center, up, width, height, fovy, znear, zfar, step)\n\n\t// render the paths in an image\n\tpaths.WriteToPNG(\"out.png\", width, height)\n\n\t// save the paths as an svg\n\tpaths.WriteToSVG(\"out.svg\", width, height)\n}\n```\n\n### The Output\n\n![Cube](http://i.imgur.com/d2dGrOJ.png)\n\n## Custom Texturing\n\nSuppose we want to draw cubes with vertical stripes on their sides, as\nshown in the skyscrapers example above. We can just define a new type\nand override the `Paths()` function.\n\n```go\ntype StripedCube struct {\n\tln.Cube\n\tStripes int\n}\n\nfunc (c *StripedCube) Paths() ln.Paths {\n\tvar paths ln.Paths\n\tx1, y1, z1 := c.Min.X, c.Min.Y, c.Min.Z\n\tx2, y2, z2 := c.Max.X, c.Max.Y, c.Max.Z\n\tfor i := 0; i \u003c= c.Stripes; i++ {\n\t\tp := float64(i) / float64(c.Stripes)\n\t\tx := x1 + (x2-x1)*p\n\t\ty := y1 + (y2-y1)*p\n\t\tpaths = append(paths, ln.Path{{x, y1, z1}, {x, y1, z2}})\n\t\tpaths = append(paths, ln.Path{{x, y2, z1}, {x, y2, z2}})\n\t\tpaths = append(paths, ln.Path{{x1, y, z1}, {x1, y, z2}})\n\t\tpaths = append(paths, ln.Path{{x2, y, z1}, {x2, y, z2}})\n\t}\n\treturn paths\n}\n```\n\nNow `StripedCube` instances can be added to the scene.\n\n## Constructive Solid Geometry (CSG)\n\nYou can easily construct complex solids using Intersection, Difference, Union.\n\n```go\nshape := ln.NewDifference(\n\tln.NewIntersection(\n\t\tln.NewSphere(ln.Vector{}, 1),\n\t\tln.NewCube(ln.Vector{-0.8, -0.8, -0.8}, ln.Vector{0.8, 0.8, 0.8}),\n\t),\n\tln.NewCylinder(0.4, -2, 2),\n\tln.NewTransformedShape(ln.NewCylinder(0.4, -2, 2), ln.Rotate(ln.Vector{1, 0, 0}, ln.Radians(90))),\n\tln.NewTransformedShape(ln.NewCylinder(0.4, -2, 2), ln.Rotate(ln.Vector{0, 1, 0}, ln.Radians(90))),\n)\n```\n\nThis is `(Sphere \u0026 Cube) - (Cylinder | Cylinder | Cylinder)`.\n\nUnfortunately, it's difficult to compute the joint formed at the boundaries of these combined shapes, so sufficient texturing is needed on the original solids for a decent result.\n\n![Example](http://i.imgur.com/gk8UtVK.gif)\n","funding_links":[],"categories":["Go","Images","图片","圖象","Relational Databases","Images 图像处理","Libraries","图像","Software","\u003cspan id=\"图片-images\"\u003e图片 Images\u003c/span\u003e"],"sub_categories":["Search and Analytic Databases","检索及分析资料库","高級控制台界面","Advanced Console UIs","SQL 查询语句构建库","Go","高级控制台界面","Vector Creation","交流","\u003cspan id=\"高级控制台用户界面-advanced-console-uis\"\u003e高级控制台用户界面 Advanced Console UIs\u003c/span\u003e"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffogleman%2Fln","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffogleman%2Fln","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffogleman%2Fln/lists"}