├── .editorconfig ├── .gitignore ├── .nojekyll ├── .npmignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── examples └── index.js ├── index.html ├── index.js ├── package-lock.json ├── package.json └── screenshot.jpg /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | types 4 | lib 5 | web_modules 6 | -------------------------------------------------------------------------------- /.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/geom-revolve/270f13645a167605a72ddeaf7e8aa787409e050e/.nojekyll -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | web_modules 2 | examples 3 | docs 4 | coverage 5 | test 6 | .github 7 | screenshot.* 8 | index.html 9 | tsconfig.json 10 | .editorconfig 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines. 4 | 5 | ## [2.0.2](https://github.com/vorg/geom-revolve/compare/v2.0.1...v2.0.2) (2024-03-14) 6 | 7 | 8 | 9 | ## [2.0.1](https://github.com/vorg/geom-revolve/compare/v2.0.0...v2.0.1) (2024-03-14) 10 | 11 | 12 | 13 | # [2.0.0](https://github.com/vorg/geom-revolve/compare/v1.0.4...v2.0.0) (2024-03-14) 14 | 15 | 16 | ### Features 17 | 18 | * add support for typed arrays ([51e1081](https://github.com/vorg/geom-revolve/commit/51e10816c0a65b3888dd34dfe3b55c50423b1694)) 19 | * use typed-array-constructor for cells ([fa2253b](https://github.com/vorg/geom-revolve/commit/fa2253b336afe4b0455eb21df4ffdc369cc854a1)) 20 | 21 | 22 | ### BREAKING CHANGES 23 | 24 | * use ES modules 25 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2015 Marcin Ignac 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 20 | OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # geom-revolve 2 | 3 | Create a simplicial complex geometry by revolving a path around Y axis. 4 | 5 |  6 | 7 | ## Installation 8 | 9 | ```bash 10 | npm install geom-revolve 11 | ``` 12 | 13 | ## Usage 14 | 15 | ```js 16 | import revolve from "geom-revolve"; 17 | 18 | const path = new Float32Array([ 19 | 0.0, 0.0, 0.0, 0.1, 0.0, 0.0, 0.2, 0.2, 0.0, 0.3, 0.5, 0.0, 0.3, 0.7, 0.0, 20 | 0.1, 0.8, 0.0, 0.1, 1.0, 0.0, 0.0, 1.0, 0.0, 21 | ]); 22 | 23 | const geometry = revolve(path); 24 | // => { positions: Float32Array(384), cells: Uint32Array(672) } 25 | ``` 26 | 27 | ## API 28 | 29 | #### `revolve(path, [numSteps], [angle]): geometry` 30 | 31 | **Parameters** 32 | 33 | - path: `TypedArray | Array | Array<[x, y, z]>` - positions defining the path to revolve. 34 | - numSteps: `number` (default: `16`) - rotation subdivisions. 35 | - angle: `number` (default: `Math.PI * 2`) - angle to rotate by. 36 | 37 | **Returns** 38 | 39 | geometry: `{ positions: TypedArray | Array<[x, y, z]>, cells: TypedArray | Array<[x, y, z]> }` - the revolved geometry. 40 | 41 | Returned cells will be either Array of Arrays or TypedArray depending on the path data. 42 | 43 | ## License 44 | 45 | MIT, see [LICENSE.md](http://github.com/vorg/geom-revolve/blob/master/LICENSE.md) for details. 46 | -------------------------------------------------------------------------------- /examples/index.js: -------------------------------------------------------------------------------- 1 | import revolve from "../index.js"; 2 | import createContext from "pex-context"; 3 | import createGUI from "pex-gui"; 4 | import { mat4 } from "pex-math"; 5 | // import computeEdges from "geom-edges"; 6 | 7 | const State = { 8 | angle: Math.PI * 2, 9 | steps: 16, 10 | pause: false, 11 | }; 12 | 13 | const W = 1280; 14 | const H = 720; 15 | const ctx = createContext({ 16 | width: W, 17 | height: H, 18 | element: document.querySelector("main"), 19 | pixelRatio: devicePixelRatio, 20 | }); 21 | 22 | const projectionMatrix = mat4.create(); 23 | const viewMatrix = mat4.create(); 24 | const modelMatrix = mat4.create(); 25 | mat4.perspective(projectionMatrix, Math.PI / 4, W / H, 0.1, 100); 26 | mat4.lookAt(viewMatrix, [0, 0.5, 2], [0, 0.5, 0]); 27 | 28 | // vase profile 29 | // _ 30 | // | 31 | // \ 32 | // | 33 | // / 34 | // _/ 35 | // 36 | 37 | // prettier-ignore 38 | const path = [ 39 | [0.0, 0.0, 0.0], 40 | [0.1, 0.0, 0.0], 41 | [0.2, 0.2, 0.0], 42 | [0.3, 0.5, 0.0], 43 | [0.3, 0.7, 0.0], 44 | [0.1, 0.8, 0.0], 45 | [0.1, 1.0, 0.0], 46 | [0.0, 1.0, 0.0], 47 | ].flat(); 48 | 49 | const cmdOptions = { 50 | attributes: { 51 | aPosition: ctx.vertexBuffer([]), 52 | }, 53 | indices: ctx.indexBuffer([]), 54 | uniforms: { 55 | uProjectionMatrix: projectionMatrix, 56 | uViewMatrix: viewMatrix, 57 | uModelMatrix: modelMatrix, 58 | }, 59 | }; 60 | 61 | const wireframeCmdOptions = { 62 | indices: ctx.indexBuffer([]), 63 | }; 64 | 65 | function computeEdges(cells, stride = 3) { 66 | const edges = new Uint32Array(cells.length * 2); 67 | 68 | let cellIndex = 0; 69 | 70 | for (let i = 0; i < cells.length; i += stride) { 71 | for (let j = 0; j < stride; j++) { 72 | const a = cells[i + j]; 73 | const b = cells[i + ((j + 1) % stride)]; 74 | edges[cellIndex] = Math.min(a, b); 75 | edges[cellIndex + 1] = Math.max(a, b); 76 | cellIndex += 2; 77 | } 78 | } 79 | return edges; 80 | } 81 | 82 | const update = () => { 83 | const g = revolve(path, State.steps, State.angle); 84 | g.edges = computeEdges(g.cells); 85 | console.log(g); 86 | 87 | ctx.update(cmdOptions.attributes.aPosition, { 88 | data: g.positions, 89 | }); 90 | ctx.update(cmdOptions.indices, { 91 | data: g.cells, 92 | }); 93 | ctx.update(wireframeCmdOptions.indices, { 94 | data: g.edges, 95 | }); 96 | }; 97 | update(); 98 | 99 | const clearCmd = { 100 | pass: ctx.pass({ 101 | clearColor: [0.2, 0.2, 0.2, 1], 102 | clearDepth: 1, 103 | }), 104 | }; 105 | 106 | const basicVert = /* glsl */ `#version 300 es 107 | uniform mat4 uProjectionMatrix; 108 | uniform mat4 uViewMatrix; 109 | uniform mat4 uModelMatrix; 110 | 111 | in vec3 aPosition; 112 | 113 | out vec4 vColor; 114 | out vec3 vPositionWorld; 115 | 116 | void main () { 117 | vColor = vec4(1.0, 0.0, 0.0, 1.0); 118 | 119 | vPositionWorld = (uModelMatrix * vec4(aPosition, 1.0)).xyz; 120 | 121 | gl_Position = uProjectionMatrix * uViewMatrix * vec4(vPositionWorld, 1.0); 122 | }`; 123 | 124 | const drawMeshCmd = { 125 | pipeline: ctx.pipeline({ 126 | vert: basicVert, 127 | frag: /* glsl */ `#version 300 es 128 | precision highp float; 129 | 130 | in vec4 vColor; 131 | in vec3 vPositionWorld; 132 | out vec4 fragColor; 133 | 134 | void main() { 135 | vec3 fdx = vec3(dFdx(vPositionWorld.x), dFdx(vPositionWorld.y), dFdx(vPositionWorld.z)); 136 | vec3 fdy = vec3(dFdy(vPositionWorld.x), dFdy(vPositionWorld.y), dFdy(vPositionWorld.z)); 137 | vec3 normal = normalize(cross(fdx, fdy)); 138 | fragColor = vec4(normal * 0.5 + 0.5, 1.0); 139 | } 140 | `, 141 | depthTest: true, 142 | }), 143 | }; 144 | 145 | const drawMeshWireframeCmd = { 146 | pipeline: ctx.pipeline({ 147 | vert: basicVert, 148 | frag: /* glsl */ `#version 300 es 149 | precision highp float; 150 | 151 | out vec4 fragColor; 152 | 153 | void main() { 154 | fragColor = vec4(1.0, 1.0, 1.0, 1.0); 155 | } 156 | `, 157 | depthTest: true, 158 | primitive: ctx.Primitive.Lines, 159 | }), 160 | }; 161 | 162 | const gui = createGUI(ctx); 163 | 164 | gui.addParam("Angle", State, "angle", { min: 0, max: Math.PI * 2 }, update); 165 | gui.addParam("Steps", State, "steps", { min: 0, max: 64, step: 1 }, update); 166 | gui.addParam("Pause", State, "pause"); 167 | 168 | let dt = 0; 169 | 170 | ctx.frame(() => { 171 | if (!State.pause) { 172 | dt += 0.005; 173 | mat4.rotate(modelMatrix, dt % 0.02, [0, 1, 0]); 174 | mat4.lookAt(viewMatrix, [0, 0.5 + Math.sin(dt) * 2, 2], [0, 0.5, 0]); 175 | } 176 | 177 | ctx.submit(clearCmd); 178 | ctx.submit(drawMeshCmd, cmdOptions); 179 | ctx.submit(drawMeshWireframeCmd, { ...cmdOptions, ...wireframeCmdOptions }); 180 | 181 | gui.draw(); 182 | }); 183 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 |