Преглед изворни кода

Add GeometryGeneratorPlugin and example

master
Palash Bansal пре 2 година
родитељ
комит
9d5bda8f86
No account linked to committer's email address

+ 138
- 160
README.md Прегледај датотеку

@@ -121,6 +121,7 @@ To make changes and run the example, click on the CodePen button on the top righ
- [@threepipe/plugin-tweakpane-editor](#threepipeplugin-tweakpane-editor) - Tweakpane Editor Plugin
- [@threepipe/plugin-extra-importers](#threepipeplugin-extra-importers) - Plugin for loading more file types supported by loaders in three.js
- [@threepipe/plugin-blend-importer](#threepipeplugin-blend-importer) - Blender to add support for loading .blend file
- [@threepipe/plugin-geometry-generator](#threepipeplugin-extra-importers) - Generate parametric geometry types that can be re-generated from UI/API.

## Getting Started

@@ -2062,11 +2063,9 @@ ThreePipe has a simple plugin system that allows you to easily add new features

[//]: # (todo: image)

Example: https://threepipe.org/examples/#tonemap-plugin/

Source Code: [src/plugins/postprocessing/TonemapPlugin.ts](./src/plugins/postprocessing/TonemapPlugin.ts)

API Reference: [TonemapPlugin](https://threepipe.org/docs/classes/TonemapPlugin.html)
[Example](https://threepipe.org/examples/#tonemap-plugin/) —
[Source Code](./src/plugins/postprocessing/TonemapPlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/TonemapPlugin.html)

TonemapPlugin adds a post-processing material extension to the ScreenPass in render manager
that applies tonemapping to the color. The tonemapping operator can be changed
@@ -2080,11 +2079,9 @@ TonemapPlugin is added by default in ThreeViewer unless `tonemap` is set to `fal

[//]: # (todo: image)

Example: https://threepipe.org/examples/#dropzone-plugin/

Source Code: [src/plugins/interaction/DropzonePlugin.ts](./src/plugins/interaction/DropzonePlugin.ts)

API Reference: [DropzonePlugin](https://threepipe.org/docs/classes/DropzonePlugin.html)
[Example](https://threepipe.org/examples/#dropzone-plugin/) —
[Source Code](./src/plugins/interaction/DropzonePlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/DropzonePlugin.html)

DropzonePlugin adds support for drag and drop of local files to automatically import, process and load them into the viewer.

@@ -2126,11 +2123,9 @@ const viewer = new ThreeViewer({

[//]: # (todo: image)

Example: https://threepipe.org/examples/#progressive-plugin/

Source Code: [src/plugins/postprocessing/ProgressivePlugin.ts](./src/plugins/pipeline/ProgressivePlugin.ts)

API Reference: [ProgressivePlugin](https://threepipe.org/docs/classes/ProgressivePlugin.html)
[Example](https://threepipe.org/examples/#progressive-plugin/) —
[Source Code](./src/plugins/pipeline/ProgressivePlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/ProgressivePlugin.html)

Progressive Plugin adds a post-render pass to blend the last frame with the current frame.

@@ -2140,11 +2135,9 @@ This is used as a dependency in other plugins for progressive rendering effect w

[//]: # (todo: image)

Example: https://threepipe.org/examples/#depth-buffer-plugin/

Source Code: [src/plugins/pipeline/DepthBufferPlugin.ts](./src/plugins/pipeline/DepthBufferPlugin.ts)

API Reference: [DepthBufferPlugin](https://threepipe.org/docs/classes/DepthBufferPlugin.html)
[Example](https://threepipe.org/examples/#depth-buffer-plugin/) —
[Source Code](./src/plugins/pipeline/DepthBufferPlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/DepthBufferPlugin.html)

Depth Buffer Plugin adds a pre-render pass to the render manager and renders a depth buffer to a target. The render target can be accessed by other plugins throughout the rendering pipeline to create effects like depth of field, SSAO, SSR, etc.

@@ -2166,11 +2159,9 @@ The depth values are based on camera near far values, which are controlled autom

[//]: # (todo: image)

Example: https://threepipe.org/examples/#normal-buffer-plugin/

Source Code: [src/plugins/pipeline/NormalBufferPlugin.ts](./src/plugins/pipeline/NormalBufferPlugin.ts)

API Reference: [NormalBufferPlugin](https://threepipe.org/docs/classes/NormalBufferPlugin.html)
[Example](https://threepipe.org/examples/#normal-buffer-plugin/) —
[Source Code](./src/plugins/pipeline/NormalBufferPlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/NormalBufferPlugin.html)

Normal Buffer Plugin adds a pre-render pass to the render manager and renders a normal buffer to a target. The render target can be accessed by other plugins throughout the rendering pipeline to create effects like SSAO, SSR, etc.

@@ -2197,11 +2188,9 @@ todo

[//]: # (todo: image)

Example: https://threepipe.org/examples/#picking-plugin/

Source Code: [src/plugins/pipeline/PickingPlugin.ts](./src/plugins/interaction/PickingPlugin.ts)

API Reference: [PickingPlugin](https://threepipe.org/docs/classes/PickingPlugin.html)
[Example](https://threepipe.org/examples/#picking-plugin/) —
[Source Code](./src/plugins/interaction/PickingPlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/PickingPlugin.html)

Picking Plugin adds support for selecting and hovering over objects in the viewer with user interactions and selection widgets.

@@ -2268,11 +2257,9 @@ pickingPlugin.addEventListener('hoverObjectChanged', (e)=>{

[//]: # (todo: image)

Example: https://threepipe.org/examples/#gltf-animation-plugin/

Source Code: [src/plugins/animation/GLTFAnimationPlugin.ts](./src/plugins/animation/GLTFAnimationPlugin.ts)

API Reference: [GLTFAnimationPlugin](https://threepipe.org/docs/classes/GLTFAnimationPlugin.html)
[Example](https://threepipe.org/examples/#gltf-animation-plugin/) —
[Source Code](./src/plugins/animation/GLTFAnimationPlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/GLTFAnimationPlugin.html)

Manages playback of GLTF animations.

@@ -2289,11 +2276,9 @@ To play individual animations, with custom choreography, use the {@link GLTFAnim

[//]: # (todo: image)

Example: https://threepipe.org/examples/#popmotion-plugin/

Source Code: [src/plugins/animation/PopmotionPlugin.ts](./src/plugins/animation/PopmotionPlugin.ts)

API Reference: [PopmotionPlugin](https://threepipe.org/docs/classes/PopmotionPlugin.html)
[Example](https://threepipe.org/examples/#popmotion-plugin/) —
[Source Code](./src/plugins/animation/PopmotionPlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/PopmotionPlugin.html)

Provides animation/tweening capabilities to the viewer using the [popmotion.io](https://popmotion.io/) library.

@@ -2356,11 +2341,9 @@ Note: The animation is started when the animate or animateAsync function is call

[//]: # (todo: image)

Example: https://threepipe.org/examples/#camera-view-plugin/

Source Code: [src/plugins/animation/CameraViewPlugin.ts](./src/plugins/animation/CameraViewPlugin.ts)

API Reference: [CameraViewPlugin](https://threepipe.org/docs/classes/CameraViewPlugin.html)
[Example](https://threepipe.org/examples/#camera-view-plugin/) —
[Source Code](./src/plugins/animation/CameraViewPlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/CameraViewPlugin.html)

CameraViewPlugin adds support to save and load camera views, which can then be animated to.
It uses PopmotionPlugin internally to animate any camera to a saved view or to loop through all the saved views.
@@ -2424,11 +2407,9 @@ cameraViewPlugin.viewLooping = false

[//]: # (todo: image)

Example: https://threepipe.org/examples/#render-target-preview/

Source Code: [src/plugins/ui/RenderTargetPreviewPlugin.ts](./src/plugins/ui/RenderTargetPreviewPlugin.ts)

API Reference: [RenderTargetPreviewPlugin](https://threepipe.org/docs/classes/RenderTargetPreviewPlugin.html)
[Example](https://threepipe.org/examples/#render-target-preview/) —
[Source Code](./src/plugins/ui/RenderTargetPreviewPlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/RenderTargetPreviewPlugin.html)

RenderTargetPreviewPlugin is a useful development and debugging plugin that renders any registered render-target to the screen in small collapsable panels.

@@ -2449,11 +2430,9 @@ previewPlugin.addTarget(()=>normalPlugin.target, 'normal', false, false)

[//]: # (todo: image)

Example: https://threepipe.org/examples/#geometry-uv-preview/

Source Code: [src/plugins/ui/GeometryUVPreviewPlugin.ts](./src/plugins/ui/GeometryUVPreviewPlugin.ts)

API Reference: [GeometryUVPreviewPlugin](https://threepipe.org/docs/classes/GeometryUVPreviewPlugin.html)
[Example](https://threepipe.org/examples/#geometry-uv-preview/) —
[Source Code](./src/plugins/ui/GeometryUVPreviewPlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/GeometryUVPreviewPlugin.html)

GeometryUVPreviewPlugin is a useful development and debugging plugin
that adds a panel to the viewer to show the UVs of a geometry.
@@ -2474,11 +2453,9 @@ previewPlugin.addGeometry(geometry, 'sphere')

[//]: # (todo: image)

Example: https://threepipe.org/examples/#frame-fade-plugin/

Source Code: [src/plugins/pipeline/FrameFadePlugin.ts](./src/plugins/pipeline/FrameFadePlugin.ts)

API Reference: [FrameFadePlugin](https://threepipe.org/docs/classes/FrameFadePlugin.html)
[Example](https://threepipe.org/examples/#frame-fade-plugin/) —
[Source Code](./src/plugins/pipeline/FrameFadePlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/FrameFadePlugin.html)

FrameFadePlugin adds a post-render pass to the render manager and blends the last frame with the current frame over time. This is useful for creating smooth transitions between frames for example when changing the camera position, material, object properties, etc to avoid a sudden jump.

@@ -2504,11 +2481,9 @@ The plugin automatically tracks `setDirty()` function calls in objects, material

[//]: # (todo: image)

Example: https://threepipe.org/examples/#vignette-plugin/

Source Code: [src/plugins/postprocessing/VignettePlugin.ts](./src/plugins/postprocessing/VignettePlugin.ts)

API Reference: [VignettePlugin](https://threepipe.org/docs/classes/VignettePlugin.html)
[Example](https://threepipe.org/examples/#vignette-plugin/) —
[Source Code](./src/plugins/postprocessing/VignettePlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/VignettePlugin.html)

VignettePlugin adds a post-processing material extension to the ScreenPass in render manager
that applies a vignette effect to the final render. The parameters `power` and `color` can be changed to customize the effect.
@@ -2532,11 +2507,9 @@ vignettePlugin.color = new Color(0.5, 0, 0)

[//]: # (todo: image)

Example: https://threepipe.org/examples/#chromatic-aberration-plugin/

Source Code: [src/plugins/postprocessing/ChromaticAberrationPlugin.ts](./src/plugins/postprocessing/ChromaticAberrationPlugin.ts)

API Reference: [ChromaticAberrationPlugin](https://threepipe.org/docs/classes/ChromaticAberrationPlugin.html)
[Example](https://threepipe.org/examples/#chromatic-aberration-plugin/) —
[Source Code](./src/plugins/postprocessing/ChromaticAberrationPlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/ChromaticAberrationPlugin.html)

ChromaticAberrationPlugin adds a post-processing material extension to the ScreenPass in render manager
that applies a chromatic-aberration effect to the final render. The parameter `intensity` can be changed to customize the effect.
@@ -2556,11 +2529,9 @@ chromaticAberrationPlugin.intensity = 0.5

[//]: # (todo: image)

Example: https://threepipe.org/examples/#filmic-grain-plugin/

Source Code: [src/plugins/postprocessing/FilmicGrainPlugin.ts](./src/plugins/postprocessing/FilmicGrainPlugin.ts)

API Reference: [FilmicGrainPlugin](https://threepipe.org/docs/classes/FilmicGrainPlugin.html)
[Example](https://threepipe.org/examples/#filmic-grain-plugin/) —
[Source Code](./src/plugins/postprocessing/FilmicGrainPlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/FilmicGrainPlugin.html)

FilmicGrainPlugin adds a post-processing material extension to the ScreenPass in render manager
that applies a filmic-grain effect to the final render. The parameters `power` and `color` can be changed to customize the effect.
@@ -2581,11 +2552,9 @@ filmicGrainPlugin.multiply = false

[//]: # (todo: image)

Example: https://threepipe.org/examples/#noise-bump-material-plugin/

Source Code: [src/plugins/material/NoiseBumpMaterialPlugin.ts](./src/plugins/material/NoiseBumpMaterialPlugin.ts)

API Reference: [NoiseBumpMaterialPlugin](https://threepipe.org/docs/classes/NoiseBumpMaterialPlugin.html)
[Example](https://threepipe.org/examples/#noise-bump-material-plugin/) —
[Source Code](./src/plugins/material/NoiseBumpMaterialPlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/NoiseBumpMaterialPlugin.html)

NoiseBumpMaterialPlugin adds a material extension to PhysicalMaterial to add support for sparkle bump / noise bump by creating procedural bump map from noise to simulate sparkle flakes.
It uses voronoise function from blender along with several additions to generate the noise for the generation.
@@ -2617,11 +2586,9 @@ material.setDirty()

[//]: # (todo: image)

Example: https://threepipe.org/examples/#custom-bump-map-plugin/

Source Code: [src/plugins/material/CustomBumpMapPlugin.ts](./src/plugins/material/CustomBumpMapPlugin.ts)

API Reference: [CustomBumpMapPlugin](https://threepipe.org/docs/classes/CustomBumpMapPlugin.html)
[Example](https://threepipe.org/examples/#custom-bump-map-plugin/) —
[Source Code](./src/plugins/material/CustomBumpMapPlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/CustomBumpMapPlugin.html)

CustomBumpMapPlugin adds a material extension to PhysicalMaterial to support custom bump maps.
A Custom bump map is similar to the built-in bump map, but allows using an extra bump map and scale to give a combined effect.
@@ -2654,11 +2621,9 @@ material.setDirty()

[//]: # (todo: image)

Example: https://threepipe.org/examples/#clearcoat-tint-plugin/

Source Code: [src/plugins/material/ClearcoatTintPlugin.ts](./src/plugins/material/ClearcoatTintPlugin.ts)

API Reference: [ClearcoatTintPlugin](https://threepipe.org/docs/classes/ClearcoatTintPlugin.html)
[Example](https://threepipe.org/examples/#clearcoat-tint-plugin/) —
[Source Code](./src/plugins/material/ClearcoatTintPlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/ClearcoatTintPlugin.html)

ClearcoatTintPlugin adds a material extension to PhysicalMaterial which adds tint and thickness to the built-in clearcoat properties.
It also adds a UI to the material to edit the settings.
@@ -2691,11 +2656,9 @@ material.setDirty()

[//]: # (todo: image)

Example: https://threepipe.org/examples/#fragment-clipping-extension-plugin/

Source Code: [src/plugins/materials/FragmentClippingExtensionPlugin.ts](./src/plugins/material/FragmentClippingExtensionPlugin.ts)

API Reference: [FragmentClippingExtensionPlugin](https://threepipe.org/docs/classes/FragmentClippingExtensionPlugin.html)
[Example](https://threepipe.org/examples/#fragment-clipping-extension-plugin/) —
[Source Code](./src/plugins/material/FragmentClippingExtensionPlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/FragmentClippingExtensionPlugin.html)

FragmentClippingExtensionPlugin adds a material extension to PhysicalMaterial to add support for fragment clipping.
Fragment clipping allows to clip fragments of the material in screen space or world space based on a circle, rectangle, plane, sphere, etc.
@@ -2729,11 +2692,9 @@ material.setDirty()

[//]: # (todo: image)

Example: https://threepipe.org/examples/#hdri-ground-plugin/

Source Code: [src/plugins/extras/HDRiGroundPlugin.ts](./src/plugins/extras/HDRiGroundPlugin.ts)

API Reference: [HDRiGroundPlugin](https://threepipe.org/docs/classes/HDRiGroundPlugin.html)
[Example](https://threepipe.org/examples/#hdri-ground-plugin/) —
[Source Code](./src/plugins/extras/HDRiGroundPlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/HDRiGroundPlugin.html)

HDRiGroundPlugin patches the background shader in the renderer to add support for ground projected environment map/skybox. Works simply by setting the background same as the environemnt and enabling the plugin.

@@ -2766,11 +2727,9 @@ Check the [example](https://threepipe.org/examples/#hdri-ground-plugin/) for a d

[//]: # (todo: image)

Example: https://threepipe.org/examples/#virtual-cameras-plugin/

Source Code: [src/plugins/rendering/VirtualCamerasPlugin.ts](./src/plugins/rendering/VirtualCamerasPlugin.ts)

API Reference: [VirtualCamerasPlugin](https://threepipe.org/docs/classes/VirtualCamerasPlugin.html)
[Example](https://threepipe.org/examples/#virtual-cameras-plugin/) —
[Source Code](./src/plugins/rendering/VirtualCamerasPlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/VirtualCamerasPlugin.html)

VirtualCamerasPlugin adds support for rendering to multiple virtual cameras in the viewer. These cameras are rendered in preRender callback just before the main camera is rendered. The virtual cameras can be added to the plugin and removed from it.

@@ -2801,11 +2760,9 @@ Check the [virtual camera](https://threepipe.org/examples/#hdri-ground-plugin/)

## Rhino3dmLoadPlugin

Example: https://threepipe.org/examples/#rhino3dm-load/

Source Code: [src/plugins/import/Rhino3dmLoadPlugin.ts](./src/plugins/import/Rhino3dmLoadPlugin.ts)

API Reference: [Rhino3dmLoadPlugin](https://threepipe.org/docs/classes/Rhino3dmLoadPlugin.html)
[Example](https://threepipe.org/examples/#rhino3dm-load/) —
[Source Code](./src/plugins/import/Rhino3dmLoadPlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/Rhino3dmLoadPlugin.html)

Adds support for loading .3dm files generated by [Rhino 3D](https://www.rhino3d.com/). This plugin includes some changes with how 3dm files are loaded in three.js. The changes are around loading layer and primitive properties when set as reference in the 3dm files.

@@ -2825,11 +2782,9 @@ const mesh = await viewer.load('file.3dm')

## PLYLoadPlugin

Example: https://threepipe.org/examples/#ply-load/

Source Code: [src/plugins/import/PLYLoadPlugin.ts](./src/plugins/import/PLYLoadPlugin.ts)

API Reference: [PLYLoadPlugin](https://threepipe.org/docs/classes/PLYLoadPlugin.html)
[Example](https://threepipe.org/examples/#ply-load/) —
[Source Code](./src/plugins/import/PLYLoadPlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/PLYLoadPlugin.html)

Adds support for loading .ply ([Polygon file format](https://en.wikipedia.org/wiki/PLY_(file_format))) files.

@@ -2842,11 +2797,9 @@ const mesh = await viewer.load('file.ply')

## USDZLoadPlugin

Example: https://threepipe.org/examples/#usdz-load/

Source Code: [src/plugins/import/USDZLoadPlugin.ts](./src/plugins/import/USDZLoadPlugin.ts)

API Reference: [USDZLoadPlugin](https://threepipe.org/docs/classes/USDZLoadPlugin.html)
[Example](https://threepipe.org/examples/#usdz-load/) —
[Source Code](./src/plugins/import/USDZLoadPlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/USDZLoadPlugin.html)

Adds support for loading .usdz and .usda ([Universal Scene Description](https://graphics.pixar.com/usd/docs/index.html)) files.

@@ -2860,11 +2813,9 @@ const mesh2 = await viewer.load('file.usda')

## STLLoadPlugin

Example: https://threepipe.org/examples/#stl-load/

Source Code: [src/plugins/import/STLLoadPlugin.ts](./src/plugins/import/STLLoadPlugin.ts)

API Reference: [STLLoadPlugin](https://threepipe.org/docs/classes/STLLoadPlugin.html)
[Example](https://threepipe.org/examples/#stl-load/) —
[Source Code](./src/plugins/import/STLLoadPlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/STLLoadPlugin.html)

Adds support for loading .stl ([Stereolithography](https://en.wikipedia.org/wiki/STL_(file_format))) files.

@@ -2877,11 +2828,9 @@ const mesh = await viewer.load('file.stl')

## KTX2LoadPlugin

Example: https://threepipe.org/examples/#ktx2-load/

Source Code: [src/plugins/import/KTX2LoadPlugin.ts](./src/plugins/import/KTX2LoadPlugin.ts)

API Reference: [KTX2LoadPlugin](https://threepipe.org/docs/classes/KTX2LoadPlugin.html)
[Example](https://threepipe.org/examples/#ktx2-load/) —
[Source Code](./src/plugins/import/KTX2LoadPlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/KTX2LoadPlugin.html)

Adds support for loading .ktx2 ([Khronos Texture](https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/) files.

@@ -2896,11 +2845,9 @@ const texture = await viewer.load('file.ktx2')

## KTXLoadPlugin

Example: https://threepipe.org/examples/#ktx-load/

Source Code: [src/plugins/import/KTXLoadPlugin.ts](./src/plugins/import/KTXLoadPlugin.ts)

API Reference: [KTXLoadPlugin](https://threepipe.org/docs/classes/KTXLoadPlugin.html)
[Example](https://threepipe.org/examples/#ktx-load/) —
[Source Code](./src/plugins/import/KTXLoadPlugin.ts) —
[API Reference](https://threepipe.org/docs/classes/KTXLoadPlugin.html)

Adds support for loading .ktx ([Khronos Texture](https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/) files.

@@ -2923,11 +2870,9 @@ These add support for integrating with other libraries, adding new features, and

[//]: # (todo: image)

Example: https://threepipe.org/examples/#tweakpane-ui-plugin/

Source Code: [plugins/tweakpane/src/TweakpaneUiPlugin.ts](plugins/tweakpane/src/TweakpaneUiPlugin.ts)

API Reference: [TweakpaneUiPlugin](https://threepipe.org/plugins/tweakpane/docs/classes/TweakpaneUiPlugin.html)
[Example](https://threepipe.org/examples/#tweakpane-ui-plugin/) —
[Source Code](./plugins/tweakpane/src/TweakpaneUiPlugin.ts) —
[API Reference](https://threepipe.org/plugins/tweakpane/docs/classes/TweakpaneUiPlugin.html)

NPM: `npm install @threepipe/plugin-tweakpane`

@@ -2959,11 +2904,9 @@ plugin.setupPlugins(TonemapPlugin, DropzonePlugin)

[//]: # (todo: image)

Example: https://threepipe.org/examples/#blueprintjs-ui-plugin/

Source Code: [plugins/blueprintjs/src/BlueprintJsUiPlugin.ts](plugins/blueprintjs/src/BlueprintJsUiPlugin.ts)

API Reference: [BlueprintJsUiPlugin](https://threepipe.org/plugins/blueprintjs/docs/classes/BlueprintJsUiPlugin.html)
[Example](https://threepipe.org/examples/#blueprintjs-ui-plugin/) —
[Source Code](./plugins/blueprintjs/src/BlueprintJsUiPlugin.ts) —
[API Reference](https://threepipe.org/plugins/blueprintjs/docs/classes/BlueprintJsUiPlugin.html)

NPM: `npm install @threepipe/plugin-blueprintjs`

@@ -2996,11 +2939,9 @@ Tweakpane Editor Plugin for ThreePipe

[//]: # (todo: image)

Example: https://threepipe.org/examples/#tweakpane-editor/

Source Code: [plugins/tweakpane-editor/src/TweakpaneEditorPlugin.ts](plugins/tweakpane-editor/src/TweakpaneEditorPlugin.ts)

API Reference: [TweakpaneEditorPlugin](https://threepipe.org/plugins/tweakpane-editor/docs/classes/TweakpaneEditorPlugin.html)
[Example](https://threepipe.org/examples/#tweakpane-editor/) —
[Source Code](./plugins/tweakpane-editor/src/TweakpaneEditorPlugin.ts) —
[API Reference](https://threepipe.org/plugins/tweakpane-editor/docs/classes/TweakpaneEditorPlugi —

NPM: `npm install @threepipe/plugin-tweakpane-editor`

@@ -3040,11 +2981,9 @@ editor.loadPlugins({

Exports several plugins to add support for various file types.

Example: https://threepipe.org/examples/#extra-importer-plugins/

Source Code: [plugins/extra-importers/src/index.ts](plugins/extra-importers/src/index.ts)

API Reference: [@threepipe/plugin-extra-importers](https://threepipe.org/plugins/extra-importers/docs)
[Example](https://threepipe.org/examples/#extra-importer-plugins/) —
[Source Code](./plugins/extra-importers/src/index.ts) —
[API Reference](https://threepipe.org/plugins/extra-importers/docs)

NPM: `npm install @threepipe/plugin-extra-importers`

@@ -3094,11 +3033,9 @@ Note: This is still a WIP.
Currently working: `Mesh`, `BufferGeometry` and basic `PointLight`.
To be added: `PhysicalMaterial`, `UnlitMaterial` (similar to blender-gltf-io plugin)

Example: https://threepipe.org/examples/#blend-load/

Source Code: [plugins/blend-importer/src/index.ts](plugins/blend-importer/src/index.ts)

API Reference: [@threepipe/plugin-blend-importer](https://threepipe.org/plugins/blend-importer/docs)
[Example](https://threepipe.org/examples/#blend-load/) —
[Source Code](./plugins/blend-importer/src/index.ts) —
[API Reference](https://threepipe.org/plugins/blend-importer/docs)

NPM: `npm install @threepipe/plugin-blend-importer`

@@ -3119,3 +3056,44 @@ const model1 = await viewer.load<IObject3D>('data:application/x-blender;base64,.

[//]: # ( TODO: The plugin should parse and references to other assets and find them relative to the .blend file or the current location.)

## @threepipe/plugin-geometry-generator

Exports [GeometryGeneratorPlugin](https://threepipe.org/plugins/geometry-generator/docs/classes/BlendLoadPlugin.html) with several Geometry generators to create parametric and updatable geometries like plane, circle, sphere, box, torus, cylinder, cone etc.

[Example](https://threepipe.org/examples/#geometry-generator-plugin/) &mdash;
[Source Code](./plugins/geometry-generator/src/index.ts) &mdash;
[API Reference](https://threepipe.org/plugins/geometry-generator/docs)

NPM: `npm install @threepipe/plugin-geometry-generator`

The generated geometries/meshes include the parameters in the userData and can be re-generated by changing the parameters from the UI or the plugin API.

Includes the following generator which inherit from [AGeometryGenerator](https://threepipe.org/plugins/geometry-generator/docs/classes/AGeometryGenerator.html):
- **plane**: [PlaneGeometryGenerator](https://threepipe.org/plugins/geometry-generator/docs/classes/PlaneGeometryGenerator),
- **sphere**: [SphereGeometryGenerator](https://threepipe.org/plugins/geometry-generator/docs/classes/SphereGeometryGenerator),
- **box**: [BoxGeometryGenerator](https://threepipe.org/plugins/geometry-generator/docs/classes/BoxGeometryGenerator),
- **circle**: [CircleGeometryGenerator](https://threepipe.org/plugins/geometry-generator/docs/classes/CircleGeometryGenerator),
- **torus**: [TorusGeometryGenerator](https://threepipe.org/plugins/geometry-generator/docs/classes/TorusGeometryGenerator),
- **cylinder**: [CylinderGeometryGenerator](https://threepipe.org/plugins/geometry-generator/docs/classes/CylinderGeometryGenerator),


Sample Usage:

```typescript
import {ThreeViewer} from 'threepipe'
import {GeometryGeneratorPlugin} from '@threepipe/plugin-geometry-generator'

const viewer = new ThreeViewer({...})
const generator = viewer.addPluginSync(GeometryGeneratorPlugin)

const sphere = generator.generateObject('sphere', {radius: 3})
viewer.scene.addObject(sphere)

// to update the geometry
generator.updateGeometry(sphere.geometry, {radius: 4, widthSegments: 100})

// to add a custom generator
generator.generators.custom = new CustomGenerator('custom') // Extend from AGeometryGenerator or implement GeometryGenerator
generator.uiConfig.uiRefresh?.()
```


+ 38
- 0
examples/geometry-generator-plugin/index.html Прегледај датотеку

@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Extra importer plugins</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

<script type="importmap">
{
"imports": {
"three": "./../../dist/index.mjs",
"threepipe": "./../../dist/index.mjs",
"@threepipe/plugin-geometry-generator": "./../../plugins/geometry-generator/dist/index.mjs",
"@threepipe/plugin-tweakpane": "./../../plugins/tweakpane/dist/index.mjs"
}
}

</script>
<style id="example-style">
html, body, #canvas-container, #mcanvas {
width: 100%;
height: 100%;
margin: 0;
overflow: hidden;
}
</style>
<script type="module" src="../examples-utils/simple-code-preview.mjs"></script>
<script id="example-script" type="module" src="./script.js" data-scripts="./script.ts;./script.js"></script>
</head>
<body>
<div id="canvas-container">
<canvas id="mcanvas"></canvas>
</div>

</body>

+ 29
- 0
examples/geometry-generator-plugin/script.ts Прегледај датотеку

@@ -0,0 +1,29 @@
import {_testFinish, CameraViewPlugin, PickingPlugin, ThreeViewer} from 'threepipe'
import {GeometryGeneratorPlugin} from '@threepipe/plugin-geometry-generator'
import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane'

async function init() {

const viewer = new ThreeViewer({
canvas: document.getElementById('mcanvas') as HTMLCanvasElement,
msaa: true,
plugins: [PickingPlugin, CameraViewPlugin],
})
const generator = viewer.addPluginSync(GeometryGeneratorPlugin)

viewer.scene.setBackgroundColor('#444466')

await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr')

console.log(generator.generators)
const sphere = generator.generateObject('sphere', {radius: 0.5, widthSegments: 32, heightSegments: 32})
viewer.scene.addObject(sphere)

const ui = viewer.addPluginSync(new TweakpaneUiPlugin(true))
ui.setupPluginUi(GeometryGeneratorPlugin)
ui.setupPluginUi(PickingPlugin)

}

init().then(_testFinish)


+ 2
- 1
examples/tweakpane-editor/index.html Прегледај датотеку

@@ -20,7 +20,8 @@
"@threepipe/plugin-tweakpane": "./../../plugins/tweakpane/dist/index.mjs",
"@threepipe/plugin-tweakpane-editor": "./../../plugins/tweakpane-editor/dist/index.mjs",
"@threepipe/plugin-extra-importers": "./../../plugins/extra-importers/dist/index.mjs",
"@threepipe/plugin-blend-importer": "./../../plugins/blend-importer/dist/index.mjs"
"@threepipe/plugin-blend-importer": "./../../plugins/blend-importer/dist/index.mjs",
"@threepipe/plugin-geometry-generator": "./../../plugins/geometry-generator/dist/index.mjs"
}
}


+ 3
- 1
examples/tweakpane-editor/script.ts Прегледај датотеку

@@ -36,6 +36,7 @@ import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane'
import {HierarchyUiPlugin, TweakpaneEditorPlugin} from '@threepipe/plugin-tweakpane-editor'
import {BlendLoadPlugin} from '@threepipe/plugin-blend-importer'
import {extraImportPlugins} from '@threepipe/plugin-extra-importers'
import {GeometryGeneratorPlugin} from '@threepipe/plugin-geometry-generator'

async function init() {

@@ -83,6 +84,7 @@ async function init() {
USDZLoadPlugin,
BlendLoadPlugin,
HierarchyUiPlugin,
GeometryGeneratorPlugin,
...extraImportPlugins,
])

@@ -92,7 +94,7 @@ async function init() {

editor.loadPlugins({
['Viewer']: [ViewerUiConfigPlugin, SceneUiConfigPlugin, DropzonePlugin, FullScreenPlugin],
['Interaction']: [HierarchyUiPlugin, PickingPlugin],
['Interaction']: [HierarchyUiPlugin, PickingPlugin, GeometryGeneratorPlugin],
['GBuffer']: [DepthBufferPlugin, NormalBufferPlugin],
['Post-processing']: [TonemapPlugin, ProgressivePlugin, FrameFadePlugin, VignettePlugin],
['Animation']: [GLTFAnimationPlugin, CameraViewPlugin],

+ 27
- 0
plugins/geometry-generator/package-lock.json Прегледај датотеку

@@ -0,0 +1,27 @@
{
"name": "@threepipe/plugins-extra-importers",
"version": "0.1.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@threepipe/plugins-extra-importers",
"version": "0.1.1",
"license": "Apache-2.0",
"dependencies": {
"threepipe": "file:./../../src/"
},
"devDependencies": {}
},
"../../src": {},
"node_modules/threepipe": {
"resolved": "../../src",
"link": true
}
},
"dependencies": {
"threepipe": {
"version": "file:../../src"
}
}
}

+ 58
- 0
plugins/geometry-generator/package.json Прегледај датотеку

@@ -0,0 +1,58 @@
{
"name": "@threepipe/plugins-geometry-generator",
"description": "Geometry generator plugin to create updatable parametric objects/geometries.",
"version": "0.1.0",
"devDependencies": {
},
"dependencies": {
"threepipe": "file:./../../src/"
},
"clean-package": {
"remove": [
"clean-package",
"scripts",
"devDependencies",
"//",
"markdown-to-html"
],
"replace": {
"dependencies": {
"threepipe": "^0.0.19"
}
}
},
"type": "module",
"main": "dist/index.js",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
"files": [
"dist",
"src"
],
"scripts": {
"new:pack": "npm run prepare && clean-package && npm pack && clean-package restore",
"new:publish": "npm run prepare && clean-package && npm publish --access public && clean-package restore",
"prepare": "npm run build",
"build": "rimraf dist && NODE_ENV=production rollup -c",
"dev": "rollup -c -w",
"docs": "rimraf docs && npx typedoc"
},
"author": "repalash <palash@shaders.app>",
"license": "Apache-2.0",
"keywords": [
"three",
"three.js",
"threepipe",
"tweakpane",
"editor",
"plugin"
],
"bugs": {
"url": "https://github.com/repalash/threepipe/issues"
},
"homepage": "https://github.com/repalash/threepipe#readme",
"repository": {
"type": "git",
"url": "git://github.com/repalash/threepipe.git"
}
}

+ 100
- 0
plugins/geometry-generator/rollup.config.mjs Прегледај датотеку

@@ -0,0 +1,100 @@
// rollup.config.js
import commonjs from '@rollup/plugin-commonjs';
import json from '@rollup/plugin-json';
import resolve from '@rollup/plugin-node-resolve';
import typescript from '@rollup/plugin-typescript';
import license from 'rollup-plugin-license'
import packageJson from './package.json' assert {type: 'json'};
import path from 'node:path'
import {fileURLToPath} from 'node:url';
import postcss from 'rollup-plugin-postcss'
import replace from '@rollup/plugin-replace'
import terser from "@rollup/plugin-terser";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const {name, version, author} = packageJson
// const {main, module, browser} = packageJson["clean-package"].replace
const isProduction = process.env.NODE_ENV === 'production'

const settings = {
globals: {
"threepipe": "threepipe",
"three": "threepipe"
},
sourcemap: true
}

export default {
input: './src/index.ts',
output: [
// {
// file: main,
// name: main,
// ...settings,
// format: 'cjs',
// plugins: [
// isProduction && terser()
// ]
// },
{
file: './dist/index.mjs',
...settings,
name: name,
format: 'es',
plugins: [
isProduction && terser()
]
},
{
file: './dist/index.js',
...settings,
name: name,
format: 'umd',
plugins: [
isProduction && terser()
]
}
],
external: Object.keys(settings.globals),
plugins: [
replace({
'from \'three\'': 'from \'threepipe\'',
delimiters: ['', ''],
}),
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
preventAssignment: true,
}),
postcss({
modules: false,
autoModules: true, // todo; issues with typescript import css, because inject is false
inject: false,
minimize: isProduction,
// Or with custom options for `postcss-modules`
}),
json(),
resolve({}),
typescript({
}),
commonjs({
include: 'node_modules/**',
extensions: ['.js'],
ignoreGlobal: false,
sourceMap: false
}),
license({
banner: `
@license
${name} v${version}
Copyright 2022<%= moment().format('YYYY') > 2022 ? '-' + moment().format('YYYY') : null %> ${author}
${packageJson.license} License
`,
thirdParty: {
output: path.join(__dirname, 'dist', 'dependencies.txt'),
includePrivate: true, // Default is false.
},
})
]
}

+ 125
- 0
plugins/geometry-generator/src/AGeometryGenerator.ts Прегледај датотеку

@@ -0,0 +1,125 @@
import {
BufferAttribute,
BufferGeometry,
BufferGeometry2,
Class,
Float32BufferAttribute,
generateUiConfig,
getOrCall,
IGeometry,
UiObjectConfig,
} from 'threepipe'

declare module 'threepipe'{
interface IGeometryUserData{
generationParams?: {
type: string
// [key: string]: any
}
}
}
export interface GeometryGenerator<T=any>{
generate(g?: IGeometry, parameters?: T): IGeometry
createUiConfig?(geometry: IGeometry): UiObjectConfig[]
}

function updateAttribute<T extends BufferAttribute=Float32BufferAttribute>(geometry: BufferGeometry, attribute: string, itemSize: number, array: any[], cls?: Class<T>) {
const attr = geometry.getAttribute(attribute) as T
const count = array.length / itemSize
if (attr && attr.count === count) {
attr.set(array)
attr.needsUpdate = true
} else {
geometry.setAttribute(attribute, new (cls ?? Float32BufferAttribute)(array, itemSize))
}
return attr
}

function updateIndices(geometry: BufferGeometry, indices: any[]) {
const index = geometry.index
if (index && index.count === indices.length) {
index.set(indices)
index.needsUpdate = true // todo: wireframe attribute is not updating
} else geometry.setIndex(indices)
}

export function updateUi(geometry: BufferGeometry, childrenUi: () => UiObjectConfig[]) {
if (!(geometry as any).uiConfig) return
let oldUi = (geometry as any).uiConfig?.children?.find((c: UiObjectConfig) => c.tags?.includes('generatedGeometry'))
if (!oldUi) {
oldUi = {
type: 'folder',
label: 'Generation Params',
tags: ['generatedGeometry'],
children: [],
}
;(geometry as any).uiConfig.children?.push(oldUi)
}
if (geometry.userData.__generationParamsUiType !== geometry.userData.generationParams.type) {
oldUi.children = childrenUi()
geometry.userData.__generationParamsUiType = geometry.userData.generationParams.type
oldUi.uiRefresh?.('postFrame', true)
}
}

export abstract class AGeometryGenerator<Tp=any> implements GeometryGenerator<Tp> {
constructor(public type: string) {
}

abstract defaultParams: Tp

createUiConfig(geometry: IGeometry): UiObjectConfig[] {
if (!geometry.userData.generationParams) return []
const ui = generateUiConfig(geometry.userData.generationParams)
// @ts-expect-error we assume only functions will be generated since its an object
.map(v=>v())
.filter(v=>getOrCall(v.property)?.[1] !== 'type')
ui.forEach(u=> {
u.onChange = () => this.generate(geometry)
})
return ui
}
protected abstract _generateData(params: Tp): {indices: number[]; vertices: number[]; normals: number[]; uvs: number[], groups?: {start: number, count: number, materialIndex: number}[]}

generate(g?: IGeometry, parameters: Partial<Tp> = {}): IGeometry|BufferGeometry2 {
const geometry: IGeometry = g ?? new BufferGeometry2()
if (!geometry.userData.generationParams) geometry.userData.generationParams = {type: this.type}
geometry.userData.generationParams.type = this.type
if ((parameters as any).type) {
console.error('Cannot change type of generated geometry here, use the plugin instead')
return geometry
}
const params = {
...this.defaultParams,
...geometry.userData.generationParams,
...parameters,
} as Tp

const {indices, vertices, normals, uvs, groups} = this._generateData(params)

// console.log(indices, vertices, normals, uvs, groups)
updateIndices(geometry, indices)
updateAttribute(geometry, 'position', 3, vertices)
updateAttribute(geometry, 'normal', 3, normals)
updateAttribute(geometry, 'uv', 2, uvs)

if (groups) {
geometry.clearGroups()
for (const group of groups) {
geometry.addGroup(group.start, group.count, group.materialIndex)
}
}

geometry.computeBoundingBox()
geometry.computeBoundingSphere()

Object.assign(geometry.userData.generationParams, params)

const childrenUi = ()=>this.createUiConfig(geometry)
updateUi(geometry, childrenUi)

geometry.setDirty()
return geometry
}

}

+ 90
- 0
plugins/geometry-generator/src/GeometryGeneratorPlugin.ts Прегледај датотеку

@@ -0,0 +1,90 @@
import {AViewerPluginSync, BufferGeometry2, IGeometry, Mesh, PhysicalMaterial, ThreeViewer} from 'threepipe'
import {TorusGeometryGenerator} from './primitives/TorusGeometryGenerator'
import {CircleGeometryGenerator} from './primitives/CircleGeometryGenerator'
import {BoxGeometryGenerator} from './primitives/BoxGeometryGenerator'
import {SphereGeometryGenerator} from './primitives/SphereGeometryGenerator'
import {PlaneGeometryGenerator} from './primitives/PlaneGeometryGenerator'
import {CylinderGeometryGenerator} from './primitives/CylinderGeometryGenerator'
import {GeometryGenerator, updateUi} from './AGeometryGenerator'

/**
* GeometryGeneratorPlugin
*
* Geometry generator plugin to create updatable parametric objects/geometries.
* Includes support for several primitive types from three.js
*/
export class GeometryGeneratorPlugin extends AViewerPluginSync<''> {
public static readonly PluginType = 'GeometryGeneratorPlugin'
enabled = true
toJSON: any = undefined

generators: Record<string, GeometryGenerator> = {
plane: new PlaneGeometryGenerator('plane'),
sphere: new SphereGeometryGenerator('sphere'),
box: new BoxGeometryGenerator('box'),
circle: new CircleGeometryGenerator('circle'),
torus: new TorusGeometryGenerator('torus'),
cylinder: new CylinderGeometryGenerator('cylinder'),
}

generateObject(type: string, params?: any) {
const generator = this.generators[type]
if (!generator) throw new Error('Unknown generator type: ' + type)
const obj = new Mesh(new BufferGeometry2(), new PhysicalMaterial())
generator.generate(obj.geometry, params)
obj.name = type
obj.geometry.name = 'Generated ' + type
return obj
}
generateGeometry(type: string, params: any, geometry?: IGeometry) {
const generator = this.generators[type]
if (!generator) throw new Error('Unknown generator type: ' + type)
const g = generator.generate(geometry, params)
g.name = 'Generated ' + type
return g
}
updateGeometry(geometry: IGeometry, params: any) {
if (!geometry.userData.generationParams?.type) throw new Error('Geometry is not generated')
const generator = this.generators[geometry.userData.generationParams.type]
if (!generator) throw new Error('Unknown generator type: ' + geometry.userData.generationParams.type)
generator.generate(geometry, params)
}

onAdded(v: ThreeViewer) {
super.onAdded(v)
v.scene.addEventListener('sceneUpdate', this._sceneUpdate)
}

protected _sceneUpdate = (e: any)=>{
if (e.hierarchyChanged) {
const obj = e.object || this._viewer?.scene.modelRoot
console.log(obj)
if (obj) {
obj.traverse((o: any)=>{
const type = o.geometry?.userData?.generationParams?.type
if (!type) return
updateUi(o.geometry, ()=>{
const gen = this.generators[type]
return gen?.createUiConfig ? gen.createUiConfig(o.geometry) ?? [] : []
})
})
}
}
}

uiConfig = {
type: 'folder',
label: 'Generate Geometry',
children:
[()=>Object.keys(this.generators).map((v) => ({
type: 'button',
label: 'Generate ' + v,
value: async() => {
const obj = this.generateObject(v)
obj.name = v
this._viewer?.scene.addObject(obj)
},
}))],
}

}

+ 36
- 0
plugins/geometry-generator/src/global.d.ts Прегледај датотеку

@@ -0,0 +1,36 @@
declare module '*.txt' {
const content: string
export default content
}
declare module '*.glsl' {
const content: string
export default content
}
declare module '*.vert' {
const content: string
export default content
}
declare module '*.frag' {
const content: string
export default content
}
declare module '*.module.scss' {
const content: any
export default content
export const stylesheet: string
}
declare module '*.module.css' {
const content: any
export default content
export const stylesheet: string
}
declare module '*.css' {
const content: string
export default content
}

// export {}

// hack for typedoc
// eslint-disable-next-line @typescript-eslint/naming-convention
// declare type OffscreenCanvas = HTMLCanvasElement

+ 9
- 0
plugins/geometry-generator/src/index.ts Прегледај датотеку

@@ -0,0 +1,9 @@
export {GeometryGeneratorPlugin} from './GeometryGeneratorPlugin'
export {AGeometryGenerator, updateUi, type GeometryGenerator} from './AGeometryGenerator'

export {BoxGeometryGenerator, type BoxGeometryGeneratorParams} from './primitives/BoxGeometryGenerator'
export {CircleGeometryGenerator, type CircleGeometryGeneratorParams} from './primitives/CircleGeometryGenerator'
export {CylinderGeometryGenerator, type CylinderGeometryGeneratorParams} from './primitives/CylinderGeometryGenerator'
export {PlaneGeometryGenerator, type PlaneGeometryGeneratorParams} from './primitives/PlaneGeometryGenerator'
export {SphereGeometryGenerator, type SphereGeometryGeneratorParams} from './primitives/SphereGeometryGenerator'
export {TorusGeometryGenerator, type TorusGeometryGeneratorParams} from './primitives/TorusGeometryGenerator'

+ 127
- 0
plugins/geometry-generator/src/primitives/BoxGeometryGenerator.ts Прегледај датотеку

@@ -0,0 +1,127 @@
import {AGeometryGenerator} from '../AGeometryGenerator'
import {Vector3} from 'threepipe'


export interface BoxGeometryGeneratorParams {
width: number,
height: number,
depth: number,
widthSegments: number,
heightSegments: number,
depthSegments: number
}

export class BoxGeometryGenerator extends AGeometryGenerator<BoxGeometryGeneratorParams> {

defaultParams = {
width: 1,
height: 1,
depth: 1,
widthSegments: 1,
heightSegments: 1,
depthSegments: 1,
}

// helper variables

protected _buildPlane(state: any, u: 'x'|'y'|'z', v: 'x'|'y'|'z', w: 'x'|'y'|'z', udir: number, vdir: number, width: number, height: number, depth: number, gridX: number, gridY: number, materialIndex: number) {
const {indices, vertices, normals, uvs, numberOfVertices, groupStart, groups} = state

const segmentWidth = width / gridX
const segmentHeight = height / gridY

const widthHalf = width / 2
const heightHalf = height / 2
const depthHalf = depth / 2

const gridX1 = gridX + 1
const gridY1 = gridY + 1

let vertexCounter = 0
let groupCount = 0

const vector = new Vector3()

// generate vertices, normals and uvs
for (let iy = 0; iy < gridY1; iy++) {
const y = iy * segmentHeight - heightHalf
for (let ix = 0; ix < gridX1; ix++) {
const x = ix * segmentWidth - widthHalf
// set values to correct vector component
vector[ u ] = x * udir
vector[ v ] = y * vdir
vector[ w ] = depthHalf
// now apply vector to vertex buffer
vertices.push(vector.x, vector.y, vector.z)
// set values to correct vector component
vector[ u ] = 0
vector[ v ] = 0
vector[ w ] = depth > 0 ? 1 : -1
// now apply vector to normal buffer
normals.push(vector.x, vector.y, vector.z)
// uvs
uvs.push(ix / gridX)
uvs.push(1 - iy / gridY)
// counters
vertexCounter += 1
}
}
// indices
// 1. you need three indices to draw a single face
// 2. a single segment consists of two faces
// 3. so we need to generate six (2*3) indices per segment
for (let iy = 0; iy < gridY; iy++) {
for (let ix = 0; ix < gridX; ix++) {
const a = numberOfVertices + ix + gridX1 * iy
const b = numberOfVertices + ix + gridX1 * (iy + 1)
const c = numberOfVertices + (ix + 1) + gridX1 * (iy + 1)
const d = numberOfVertices + (ix + 1) + gridX1 * iy
// faces
indices.push(a, b, d)
indices.push(b, c, d)
// increase counter
groupCount += 6
}
}
// add a group to the geometry. this will ensure multi material support
groups.push({start: groupStart, count: groupCount, materialIndex})
// calculate new start value for groups
state.groupStart += groupCount
// update total number of vertices
state.numberOfVertices += vertexCounter
}

protected _generateData(params: BoxGeometryGeneratorParams) {
const {width, height, depth} = params
let {widthSegments, heightSegments, depthSegments} = params

// segments
widthSegments = Math.floor(widthSegments)
heightSegments = Math.floor(heightSegments)
depthSegments = Math.floor(depthSegments)

// buffers

const state = {
indices: [],
vertices: [],
normals: [],
uvs: [],
numberOfVertices: 0,
groupStart: 0,
groups: [],
}

// build each side of the box geometry

this._buildPlane(state, 'z', 'y', 'x', -1, -1, depth, height, width, depthSegments, heightSegments, 0) // px
this._buildPlane(state, 'z', 'y', 'x', 1, -1, depth, height, -width, depthSegments, heightSegments, 1) // nx
this._buildPlane(state, 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2) // py
this._buildPlane(state, 'x', 'z', 'y', 1, -1, width, depth, -height, widthSegments, depthSegments, 3) // ny
this._buildPlane(state, 'x', 'y', 'z', 1, -1, width, height, depth, widthSegments, heightSegments, 4) // pz
this._buildPlane(state, 'x', 'y', 'z', -1, -1, width, height, -depth, widthSegments, heightSegments, 5) // nz

return state
}

}

+ 79
- 0
plugins/geometry-generator/src/primitives/CircleGeometryGenerator.ts Прегледај датотеку

@@ -0,0 +1,79 @@
import {AGeometryGenerator} from '../AGeometryGenerator'
import {Vector2, Vector3} from 'threepipe'


export interface CircleGeometryGeneratorParams {
radius: number,
segments: number,
thetaStart: number,
thetaLength: number
}

export class CircleGeometryGenerator extends AGeometryGenerator<CircleGeometryGeneratorParams> {

defaultParams = {
radius: 1,
segments: 32,
thetaStart: 0,
thetaLength: Math.PI * 2,
}

protected _generateData(params: CircleGeometryGeneratorParams) {
const {radius, thetaStart, thetaLength} = params

const segments = Math.max(3, params.segments)

// buffers

const indices = []
const vertices = []
const normals = []
const uvs = []

// helper variables

const vertex = new Vector3()
const uv = new Vector2()

// center point

vertices.push(0, 0, 0)
normals.push(0, 0, 1)
uvs.push(0.5, 0.5)

for (let s = 0, i = 3; s <= segments; s++, i += 3) {

const segment = thetaStart + s / segments * thetaLength

// vertex

vertex.x = radius * Math.cos(segment)
vertex.y = radius * Math.sin(segment)

vertices.push(vertex.x, vertex.y, vertex.z)

// normal

normals.push(0, 0, 1)

// uvs

uv.x = (vertices[ i ] / radius + 1) / 2
uv.y = (vertices[ i + 1 ] / radius + 1) / 2

uvs.push(uv.x, uv.y)

}

// indices

for (let i = 1; i <= segments; i++) {

indices.push(i, i + 1, 0)

}

return {indices, vertices, normals, uvs}
}

}

+ 193
- 0
plugins/geometry-generator/src/primitives/CylinderGeometryGenerator.ts Прегледај датотеку

@@ -0,0 +1,193 @@
import {AGeometryGenerator} from '../AGeometryGenerator'
import {Vector2, Vector3} from 'threepipe'


export interface CylinderGeometryGeneratorParams {
radiusTop: number,
radiusBottom: number,
height: number,
radialSegments: number,
heightSegments: number,
openEnded: boolean,
thetaStart: number,
thetaLength: number
}

export class CylinderGeometryGenerator extends AGeometryGenerator<CylinderGeometryGeneratorParams> {

defaultParams = {
radiusTop: 1,
radiusBottom: 1,
height: 1,
radialSegments: 32,
heightSegments: 1,
openEnded: false,
thetaStart: 0,
thetaLength: Math.PI * 2,
}

protected _generateTorso(state: any) {
const {radiusTop, radiusBottom, height,
radialSegments, heightSegments,
thetaStart, thetaLength, indexArray, indices, groups,
vertices, normals, uvs, groupStart, halfHeight} = state

const normal = new Vector3()
const vertex = new Vector3()

let groupCount = 0

// this will be used to calculate the normal
const slope = (radiusBottom - radiusTop) / height

// generate vertices, normals and uvs

for (let y = 0; y <= heightSegments; y++) {
const indexRow = []
const v = y / heightSegments
// calculate the radius of the current row
const radius = v * (radiusBottom - radiusTop) + radiusTop
for (let x = 0; x <= radialSegments; x++) {
const u = x / radialSegments
const theta = u * thetaLength + thetaStart
const sinTheta = Math.sin(theta)
const cosTheta = Math.cos(theta)
// vertex
vertex.x = radius * sinTheta
vertex.y = -v * height + halfHeight
vertex.z = radius * cosTheta
vertices.push(vertex.x, vertex.y, vertex.z)
// normal
normal.set(sinTheta, slope, cosTheta).normalize()
normals.push(normal.x, normal.y, normal.z)
// uv
uvs.push(u, 1 - v)
// save index of vertex in respective row
indexRow.push(state.index++)
}
// now save vertices of the row in our index array
indexArray.push(indexRow)
}
// generate indices
for (let x = 0; x < radialSegments; x++) {
for (let y = 0; y < heightSegments; y++) {
// we use the index array to access the correct indices
const a = indexArray[ y ][ x ]
const b = indexArray[ y + 1 ][ x ]
const c = indexArray[ y + 1 ][ x + 1 ]
const d = indexArray[ y ][ x + 1 ]
// faces
indices.push(a, b, d)
indices.push(b, c, d)
// update group counter
groupCount += 6
}
}
// add a group to the geometry. this will ensure multi material support
groups.push({start: groupStart, count: groupCount, materialIndex: 0})
// calculate new start value for groups
state.groupStart += groupCount
}
protected _generateCap(state: any, top: boolean) {
const {radiusTop, radiusBottom,
radialSegments,
thetaStart, thetaLength, indices, groups,
vertices, normals, uvs, groupStart, halfHeight} = state
// save the index of the first center vertex
const centerIndexStart = state.index
const uv = new Vector2()
const vertex = new Vector3()
let groupCount = 0
const radius = top === true ? radiusTop : radiusBottom
const sign = top === true ? 1 : -1
// first we generate the center vertex data of the cap.
// because the geometry needs one set of uvs per face,
// we must generate a center vertex per face/segment
for (let x = 1; x <= radialSegments; x++) {
// vertex
vertices.push(0, halfHeight * sign, 0)
// normal
normals.push(0, sign, 0)
// uv
uvs.push(0.5, 0.5)
// increase index
state.index++
}
// save the index of the last center vertex
const centerIndexEnd = state.index
// now we generate the surrounding vertices, normals and uvs
for (let x = 0; x <= radialSegments; x++) {
const u = x / radialSegments
const theta = u * thetaLength + thetaStart
const cosTheta = Math.cos(theta)
const sinTheta = Math.sin(theta)
// vertex
vertex.x = radius * sinTheta
vertex.y = halfHeight * sign
vertex.z = radius * cosTheta
vertices.push(vertex.x, vertex.y, vertex.z)
// normal
normals.push(0, sign, 0)
// uv
uv.x = cosTheta * 0.5 + 0.5
uv.y = sinTheta * 0.5 * sign + 0.5
uvs.push(uv.x, uv.y)
// increase index
state.index++
}
// generate indices
for (let x = 0; x < radialSegments; x++) {
const c = centerIndexStart + x
const i = centerIndexEnd + x
if (top === true) {
// face top
indices.push(i, i + 1, c)
} else {
// face bottom
indices.push(i + 1, i, c)
}
groupCount += 3
}
// add a group to the geometry. this will ensure multi material support
groups.push({start: groupStart, count: groupCount, materialIndex: top === true ? 1 : 2})
// calculate new start value for groups
state.groupStart += groupCount
}

protected _generateData(params: CylinderGeometryGeneratorParams) {
let {radialSegments, heightSegments} = params

radialSegments = Math.floor(radialSegments)
heightSegments = Math.floor(heightSegments)

const state = {
indices: [],
vertices: [],
normals: [],
uvs: [],
numberOfVertices: 0,
groupStart: 0,
groups: [],
index: 0,
indexArray: [],
halfHeight: params.height / 2,
...params,
radialSegments,
heightSegments,
}

// generate geometry

this._generateTorso(state)

if (params.openEnded === false) {

if (params.radiusTop > 0) this._generateCap(state, true)
if (params.radiusBottom > 0) this._generateCap(state, false)

}

return state
}

}

+ 61
- 0
plugins/geometry-generator/src/primitives/PlaneGeometryGenerator.ts Прегледај датотеку

@@ -0,0 +1,61 @@
import {AGeometryGenerator} from '../AGeometryGenerator'


export interface PlaneGeometryGeneratorParams {
width: number,
height: number,
widthSegments: number,
heightSegments: number
}

export class PlaneGeometryGenerator extends AGeometryGenerator<PlaneGeometryGeneratorParams> {

defaultParams = {
width: 1,
height: 1,
widthSegments: 2,
heightSegments: 2,
}

protected _generateData(params: PlaneGeometryGeneratorParams) {
const widthHalf = params.width / 2
const heightHalf = params.height / 2

const gridX = Math.floor(params.widthSegments)
const gridY = Math.floor(params.heightSegments)

const gridX1 = gridX + 1
const gridY1 = gridY + 1

const segmentWidth = params.width / gridX
const segmentHeight = params.height / gridY

const indices = []
const vertices = []
const normals = []
const uvs = []

for (let iy = 0; iy < gridY1; iy++) {
const y = iy * segmentHeight - heightHalf
for (let ix = 0; ix < gridX1; ix++) {
const x = ix * segmentWidth - widthHalf
vertices.push(x, -y, 0)
normals.push(0, 0, 1)
uvs.push(ix / gridX)
uvs.push(1 - iy / gridY)
}
}
for (let iy = 0; iy < gridY; iy++) {
for (let ix = 0; ix < gridX; ix++) {
const a = ix + gridX1 * iy
const b = ix + gridX1 * (iy + 1)
const c = ix + 1 + gridX1 * (iy + 1)
const d = ix + 1 + gridX1 * iy
indices.push(a, b, d)
indices.push(b, c, d)
}
}
return {indices, vertices, normals, uvs}
}

}

+ 90
- 0
plugins/geometry-generator/src/primitives/SphereGeometryGenerator.ts Прегледај датотеку

@@ -0,0 +1,90 @@
import {Vector3} from 'threepipe'
import {AGeometryGenerator} from '../AGeometryGenerator'


export interface SphereGeometryGeneratorParams {
radius: number,
widthSegments: number,
heightSegments: number,
phiStart: number,
phiLength: number,
thetaStart: number,
thetaLength: number,
}

export class SphereGeometryGenerator extends AGeometryGenerator<SphereGeometryGeneratorParams> {

defaultParams = {
radius: 1,
widthSegments: 32,
heightSegments: 16,
phiStart: 0,
phiLength: Math.PI * 2,
thetaStart: 0,
thetaLength: Math.PI,
}

protected _generateData(params: SphereGeometryGeneratorParams) {
const {radius, phiStart, phiLength, thetaStart, thetaLength} = params
let {widthSegments, heightSegments} = params

widthSegments = Math.max(3, Math.floor(widthSegments))
heightSegments = Math.max(2, Math.floor(heightSegments))

const thetaEnd = Math.min(thetaStart + thetaLength, Math.PI)

let index = 0
const grid = []

const vertex = new Vector3()
const normal = new Vector3()

// buffers

const indices = []
const vertices = []
const normals = []
const uvs = []

// generate vertices, normals and uvs
for (let iy = 0; iy <= heightSegments; iy++) {
const verticesRow = []
const v = iy / heightSegments
// special case for the poles
let uOffset = 0
if (iy === 0 && thetaStart === 0) {
uOffset = 0.5 / widthSegments
} else if (iy === heightSegments && thetaEnd === Math.PI) {
uOffset = -0.5 / widthSegments
}
for (let ix = 0; ix <= widthSegments; ix++) {
const u = ix / widthSegments
// vertex
vertex.x = -radius * Math.cos(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength)
vertex.y = radius * Math.cos(thetaStart + v * thetaLength)
vertex.z = radius * Math.sin(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength)
vertices.push(vertex.x, vertex.y, vertex.z)
// normal
normal.copy(vertex).normalize()
normals.push(normal.x, normal.y, normal.z)
// uv
uvs.push(u + uOffset, 1 - v)
verticesRow.push(index++)
}
grid.push(verticesRow)
}
// indices
for (let iy = 0; iy < heightSegments; iy++) {
for (let ix = 0; ix < widthSegments; ix++) {
const a = grid[iy][ix + 1]
const b = grid[iy][ix]
const c = grid[iy + 1][ix]
const d = grid[iy + 1][ix + 1]
if (iy !== 0 || thetaStart > 0) indices.push(a, b, d)
if (iy !== heightSegments - 1 || thetaEnd < Math.PI) indices.push(b, c, d)
}
}
return {indices, vertices, normals, uvs}
}

}

+ 102
- 0
plugins/geometry-generator/src/primitives/TorusGeometryGenerator.ts Прегледај датотеку

@@ -0,0 +1,102 @@
import {AGeometryGenerator} from '../AGeometryGenerator'
import {Vector3} from 'threepipe'


export interface TorusGeometryGeneratorParams {
radius: number,
tube: number,
radialSegments: number,
tubularSegments: number,
arc: number
}

export class TorusGeometryGenerator extends AGeometryGenerator<TorusGeometryGeneratorParams> {

defaultParams = {
radius: 1,
tube: 0.4,
radialSegments: 12,
tubularSegments: 48,
arc: Math.PI * 2,
}

protected _generateData(params: TorusGeometryGeneratorParams) {
const {radius, tube, arc} = params
let {radialSegments, tubularSegments} = params

radialSegments = Math.floor(radialSegments)
tubularSegments = Math.floor(tubularSegments)

// buffers

const indices = []
const vertices = []
const normals = []
const uvs = []

// helper variables

const center = new Vector3()
const vertex = new Vector3()
const normal = new Vector3()

// generate vertices, normals and uvs

for (let j = 0; j <= radialSegments; j++) {

for (let i = 0; i <= tubularSegments; i++) {

const u = i / tubularSegments * arc
const v = j / radialSegments * Math.PI * 2

// vertex

vertex.x = (radius + tube * Math.cos(v)) * Math.cos(u)
vertex.y = (radius + tube * Math.cos(v)) * Math.sin(u)
vertex.z = tube * Math.sin(v)

vertices.push(vertex.x, vertex.y, vertex.z)

// normal

center.x = radius * Math.cos(u)
center.y = radius * Math.sin(u)
normal.subVectors(vertex, center).normalize()

normals.push(normal.x, normal.y, normal.z)

// uv

uvs.push(i / tubularSegments)
uvs.push(j / radialSegments)

}

}

// generate indices

for (let j = 1; j <= radialSegments; j++) {

for (let i = 1; i <= tubularSegments; i++) {

// indices

const a = (tubularSegments + 1) * j + i - 1
const b = (tubularSegments + 1) * (j - 1) + i - 1
const c = (tubularSegments + 1) * (j - 1) + i
const d = (tubularSegments + 1) * j + i

// faces

indices.push(a, b, d)
indices.push(b, c, d)

}

}

return {indices, vertices, normals, uvs}
}

}

+ 44
- 0
plugins/geometry-generator/tsconfig.json Прегледај датотеку

@@ -0,0 +1,44 @@
{
"compilerOptions": {
"baseUrl": "./src",
"rootDir": "./src",
"allowJs": false,
"checkJs": false,
"skipLibCheck": true,
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
"isolatedModules": true,
"module": "es2020",
"noImplicitAny": true,
"declaration": true,
"declarationMap": true,
"declarationDir": "dist",
"outDir": "dist",
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"removeComments": false,
"preserveConstEnums": true,
"moduleResolution": "node",
"emitDecoratorMetadata": false,
"sourceMap": true,
"target": "ES2020",
"strictNullChecks": true,
"lib": [
"es2020",
"esnext",
"dom"
],
"paths": {
"three": ["threepipe"]
}
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"**/*.spec.ts",
"dist"
]
}

+ 10
- 0
plugins/geometry-generator/typedoc.json Прегледај датотеку

@@ -0,0 +1,10 @@
{
"extends": [
"../../typedoc.json"
],
"entryPoints": [
"src/index.ts"
],
"name": "Threepipe Geometry Generator Plugin",
"readme": "none"
}

+ 1
- 1
scripts/build-plugins.mjs Прегледај датотеку

@@ -1,5 +1,5 @@
import {execEachPlugin} from "./utils.mjs";

// Each plugin should have "prepare" that will also build the plugin
execEachPlugin('npm install') // install dependencies
execEachPlugin('npm ci') // install dependencies
execEachPlugin('npm run docs')

Loading…
Откажи
Сачувај