Przeglądaj źródła

Merge remote-tracking branch 'origin/master'

master
Palash Bansal 2 lat temu
rodzic
commit
7ddc4d6026
No account linked to committer's email address
98 zmienionych plików z 3754 dodań i 628 usunięć
  1. 1
    2
      .eslintrc.cjs
  2. 1854
    214
      README.md
  3. 1
    0
      examples/3dm-to-glb/index.html
  4. 1
    0
      examples/camera-uiconfig/index.html
  5. 1
    0
      examples/custom-pipeline/index.html
  6. 1
    0
      examples/depth-buffer-plugin/index.html
  7. 1
    0
      examples/directional-light/index.html
  8. 1
    0
      examples/drc-load/index.html
  9. 1
    0
      examples/dropzone-plugin/index.html
  10. 1
    0
      examples/exr-load/index.html
  11. 48
    0
      examples/extra-importer-plugins/index.html
  12. 97
    0
      examples/extra-importer-plugins/script.ts
  13. 1
    0
      examples/fbx-load/index.html
  14. 1
    0
      examples/frame-fade-plugin/index.html
  15. 1
    0
      examples/fullscreen-plugin/index.html
  16. 35
    0
      examples/geometry-uv-preview/index.html
  17. 35
    0
      examples/geometry-uv-preview/script.ts
  18. 1
    0
      examples/glb-export/index.html
  19. 1
    1
      examples/gltf-animation-page-scroll/index.html
  20. 1
    0
      examples/gltf-animation-plugin/index.html
  21. 1
    0
      examples/gltf-camera-animation/index.html
  22. 1
    0
      examples/gltf-load/index.html
  23. 1
    0
      examples/gltf-transmission-test/index.html
  24. 1
    0
      examples/half-float-hdr-test/index.html
  25. 1
    0
      examples/hdr-load/index.html
  26. 1
    0
      examples/hdr-to-exr/index.html
  27. 1
    0
      examples/image-load/index.html
  28. 1
    0
      examples/image-snapshot-export/index.html
  29. 1
    0
      examples/import-test/index.html
  30. 4
    1
      examples/index.html
  31. 1
    0
      examples/ktx-load/index.html
  32. 1
    0
      examples/ktx2-load/index.html
  33. 1
    0
      examples/material-uiconfig/index.html
  34. 1
    0
      examples/normal-buffer-plugin/index.html
  35. 1
    0
      examples/obj-mtl-load/index.html
  36. 1
    0
      examples/obj-to-glb/index.html
  37. 1
    0
      examples/object-uiconfig/index.html
  38. 1
    0
      examples/parallel-asset-import/index.html
  39. 1
    0
      examples/ply-load/index.html
  40. 1
    0
      examples/pmat-material-export/index.html
  41. 1
    0
      examples/popmotion-plugin/index.html
  42. 1
    0
      examples/progressive-plugin/index.html
  43. 1
    0
      examples/render-target-export/index.html
  44. 1
    0
      examples/render-target-preview/index.html
  45. 1
    0
      examples/rhino3dm-load/index.html
  46. 1
    0
      examples/scene-uiconfig/index.html
  47. 1
    0
      examples/sphere-half-float-test/index.html
  48. 1
    0
      examples/sphere-msaa-test/index.html
  49. 1
    0
      examples/sphere-rgbm-test/index.html
  50. 1
    0
      examples/stl-load/index.html
  51. 1
    0
      examples/tonemap-plugin/index.html
  52. 4
    1
      examples/tweakpane-editor/index.html
  53. 9
    5
      examples/tweakpane-editor/script.ts
  54. 1
    0
      examples/uint8-rgbm-hdr-test/index.html
  55. 35
    0
      examples/usdz-load/index.html
  56. 31
    0
      examples/usdz-load/script.ts
  57. 1
    0
      examples/viewer-uiconfig/index.html
  58. 1
    0
      examples/z-prepass/index.html
  59. 8
    8
      package-lock.json
  60. 4
    4
      package.json
  61. 30
    0
      plugins/extra-importers/package-lock.json
  62. 58
    0
      plugins/extra-importers/package.json
  63. 97
    0
      plugins/extra-importers/rollup.config.mjs
  64. 36
    0
      plugins/extra-importers/src/global.d.ts
  65. 244
    0
      plugins/extra-importers/src/index.ts
  66. 41
    0
      plugins/extra-importers/tsconfig.json
  67. 10
    0
      plugins/extra-importers/typedoc.json
  68. 36
    0
      plugins/plugin-template-rollup/package-lock.json
  69. 60
    0
      plugins/plugin-template-rollup/package.json
  70. 97
    0
      plugins/plugin-template-rollup/rollup.config.mjs
  71. 3
    0
      plugins/plugin-template-rollup/src/SamplePlugin.css
  72. 19
    0
      plugins/plugin-template-rollup/src/SamplePlugin.ts
  73. 36
    0
      plugins/plugin-template-rollup/src/global.d.ts
  74. 1
    0
      plugins/plugin-template-rollup/src/index.ts
  75. 41
    0
      plugins/plugin-template-rollup/tsconfig.json
  76. 10
    0
      plugins/plugin-template-rollup/typedoc.json
  77. 3
    1
      plugins/tweakpane/src/tpImageInputGenerator.ts
  78. 4
    3
      scripts/utils.mjs
  79. 4
    1
      src/assetmanager/AssetManager.ts
  80. 1
    0
      src/core/IRenderer.ts
  81. 1
    1
      src/core/IScene.ts
  82. 106
    91
      src/core/object/RootScene.ts
  83. 24
    0
      src/plugins/base/BaseImporterPlugin.ts
  84. 6
    10
      src/plugins/import/KTX2LoadPlugin.ts
  85. 3
    17
      src/plugins/import/KTXLoadPlugin.ts
  86. 7
    19
      src/plugins/import/PLYLoadPlugin.ts
  87. 3
    18
      src/plugins/import/Rhino3dmLoadPlugin.ts
  88. 7
    18
      src/plugins/import/STLLoadPlugin.ts
  89. 38
    0
      src/plugins/import/USDZLoadPlugin.ts
  90. 3
    0
      src/plugins/index.ts
  91. 49
    0
      src/plugins/ui/GeometryUVPreviewPlugin.css
  92. 166
    0
      src/plugins/ui/GeometryUVPreviewPlugin.ts
  93. 16
    2
      src/rendering/RenderManager.ts
  94. 34
    1
      src/utils/CustomContextMenu.ts
  95. 1
    0
      src/utils/serialization.ts
  96. 9
    0
      src/utils/shader-helpers.ts
  97. 237
    209
      src/viewer/ThreeViewer.ts
  98. 1
    1
      src/viewer/version.ts

+ 1
- 2
.eslintrc.cjs Wyświetl plik

'ecmaVersion': 2021, // Allows for the parsing of modern ECMAScript features 'ecmaVersion': 2021, // Allows for the parsing of modern ECMAScript features
'sourceType': 'module', // Allows for the use of imports 'sourceType': 'module', // Allows for the use of imports
'project': ['./tsconfig.json', './examples/tsconfig.json', 'project': ['./tsconfig.json', './examples/tsconfig.json',
'./plugins/tweakpane-editor/tsconfig.json',
'./plugins/tweakpane/tsconfig.json',
'./plugins/**/tsconfig.json',
], ],
'tsconfigRootDir': './', 'tsconfigRootDir': './',
}, },

+ 1854
- 214
README.md
Plik diff jest za duży
Wyświetl plik


+ 1
- 0
examples/3dm-to-glb/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Rhino 3DM To GLB</title> <title>Rhino 3DM To GLB</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/camera-uiconfig/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Camera UiConfig</title> <title>Camera UiConfig</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/custom-pipeline/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Custom Pipeline</title> <title>Custom Pipeline</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/depth-buffer-plugin/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Depth Buffer Plugin</title> <title>Depth Buffer Plugin</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/directional-light/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Directional Light</title> <title>Directional Light</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/drc-load/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>DRACO(DRC) Load</title> <title>DRACO(DRC) Load</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/dropzone-plugin/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Dropzone Plugin</title> <title>Dropzone Plugin</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/exr-load/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>EXR Load</title> <title>EXR Load</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 48
- 0
examples/extra-importer-plugins/index.html Wyświetl plik

<!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-extra-importers": "./../../plugins/extra-importers/dist/index.mjs"
}
}

</script>
<style id="example-style">
html, body, #canvas-container, #mcanvas {
width: 100%;
height: 100%;
margin: 0;
overflow: hidden;
}
p{
position: absolute;
top: 5%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 1.25em;
color: #8cd55b;
font-family: sans-serif;
pointer-events: none;
}
</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">
<p>Drop .3ds .3mf .collada .amf .bvh .vox .gcode .mdd .pcd .tilt .wrl .mpd .vtk .xyz files here</p>
<canvas id="mcanvas"></canvas>
</div>

</body>

+ 97
- 0
examples/extra-importer-plugins/script.ts Wyświetl plik

import {_testFinish, GLTFAnimationPlugin, HemisphereLight, ImportAddOptions, IObject3D, ThreeViewer} from 'threepipe'
import {
AMFLoadPlugin,
BVHLoadPlugin,
ColladaLoadPlugin,
GCodeLoadPlugin,
LDrawLoadPlugin,
MDDLoadPlugin,
PCDLoadPlugin,
TDSLoadPlugin,
ThreeMFLoadPlugin,
TiltLoadPlugin,
VOXLoadPlugin,
VRMLLoadPlugin,
VTKLoadPlugin,
XYZLoadPlugin,
} from '@threepipe/plugin-extra-importers'

async function init() {

const viewer = new ThreeViewer({
canvas: document.getElementById('mcanvas') as HTMLCanvasElement,
msaa: true,
dropzone: {
addOptions: {
disposeSceneObjects: true,
},
},
})
viewer.addPluginsSync([
GLTFAnimationPlugin,

TDSLoadPlugin,
ThreeMFLoadPlugin,
ColladaLoadPlugin,
AMFLoadPlugin,
GCodeLoadPlugin,
BVHLoadPlugin,
VOXLoadPlugin,
MDDLoadPlugin,
PCDLoadPlugin,
TiltLoadPlugin,
VRMLLoadPlugin,
LDrawLoadPlugin,
VTKLoadPlugin,
XYZLoadPlugin,

])

viewer.getPlugin(GLTFAnimationPlugin)!.autoplayOnLoad = true

viewer.scene.mainCamera.autoNearFar = false

viewer.scene.setBackgroundColor('#555555')
viewer.scene.addObject(new HemisphereLight(0xffffff, 0x444444, 2))
await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr')

const urls = [
'https://threejs.org/examples/models/3ds/portalgun/portalgun.3ds',
'https://threejs.org/examples/models/3mf/cube_gears.3mf',
'https://threejs.org/examples/models/collada/elf/elf.dae',
'https://threejs.org/examples/models/amf/rook.amf',
'https://threejs.org/examples/models/gcode/benchy.gcode',
'https://threejs.org/examples/models/bvh/pirouette.bvh',
'https://threejs.org/examples/models/vox/monu10.vox',
'https://threejs.org/examples/models/mdd/cube.mdd',
'https://threejs.org/examples/models/pcd/binary/Zaghetto.pcd',
'https://threejs.org/examples/models/tilt/BRUSH_DOME.tilt',
'https://threejs.org/examples/models/ldraw/officialLibrary/models/car.ldr_Packed.mpd',
'https://threejs.org/examples/models/vtk/bunny.vtk',
'https://threejs.org/examples/models/vtk/cube_binary.vtp',
'https://threejs.org/examples/models/xyz/helix_201.xyz',
]

const options: ImportAddOptions = {
autoScale: true,
autoCenter: true,
autoScaleRadius: 0.5,
clearSceneObjects: false,
}
let i = 0
const models = await Promise.allSettled(urls.map(async url =>
viewer.load<IObject3D>(url, options).then(res => {
if (!res) return
res.position.set(i % 4 - 1.5, 0, Math.floor(i / 4) - 1.5).multiplyScalar(1)
res.setDirty()
i++
return res
})))

console.log(models)


}

init().then(_testFinish)


+ 1
- 0
examples/fbx-load/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>FBX Load</title> <title>FBX Load</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/frame-fade-plugin/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Frame Fade Plugin</title> <title>Frame Fade Plugin</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/fullscreen-plugin/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Fullscreen Plugin</title> <title>Fullscreen Plugin</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 35
- 0
examples/geometry-uv-preview/index.html Wyświetl plik

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Render Target Preview</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": {
"threepipe": "./../../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>

+ 35
- 0
examples/geometry-uv-preview/script.ts Wyświetl plik

import {_testFinish, GeometryUVPreviewPlugin, IObject3D, ThreeViewer} from 'threepipe'

const viewer = new ThreeViewer({
canvas: document.getElementById('mcanvas') as HTMLCanvasElement,
rgbm: true,
})

async function init() {

const uvPreview = viewer.addPluginSync(GeometryUVPreviewPlugin)

await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr')
const result = await viewer.load<IObject3D>('https://threejs.org/examples/models/gltf/IridescentDishWithOlives.glb', {
autoCenter: true,
autoScale: true,
})

const added = false

result?.traverse((obj) => {
if (obj.geometry && !added) {
// added = true
uvPreview.addGeometry(obj.geometry, obj.name)
}
})


// uvPreview.add(()=>depth.target, 'depth', false, true)
// uvPreview.add(()=>normal.target, 'normal', false, false)
// uvPreview.add(()=>viewer.renderManager.composerTarget, 'composer-1', false, false)
// uvPreview.add(()=>viewer.renderManager.composerTarget2, 'composer-2', false, false)

}

init().then(_testFinish)

+ 1
- 0
examples/glb-export/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>GLB Export</title> <title>GLB Export</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 1
examples/gltf-animation-page-scroll/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>GLTF Animation Page Scroll</title> <title>GLTF Animation Page Scroll</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/gltf-animation-plugin/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>GLTF Animation Plugin</title> <title>GLTF Animation Plugin</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/gltf-camera-animation/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>GLTF Camera Animation</title> <title>GLTF Camera Animation</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/gltf-load/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>GLTF Load</title> <title>GLTF Load</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/gltf-transmission-test/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>GLTF Transmission Test</title> <title>GLTF Transmission Test</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/half-float-hdr-test/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Half float HDR Test</title> <title>Half float HDR Test</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/hdr-load/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>HDR Load</title> <title>HDR Load</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/hdr-to-exr/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>HDR To EXR</title> <title>HDR To EXR</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/image-load/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Image Load</title> <title>Image Load</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/image-snapshot-export/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Image Snapshot Export</title> <title>Image Snapshot Export</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/import-test/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Basic Lib Import Test</title> <title>Basic Lib Import Test</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 4
- 1
examples/index.html Wyświetl plik

<li><a href="./hdr-load/">HDR Load </a></li> <li><a href="./hdr-load/">HDR Load </a></li>
<li><a href="./exr-load/">EXR Load </a></li> <li><a href="./exr-load/">EXR Load </a></li>
<li><a href="./image-load/">Image(png, jpeg, svg, ico, webp, avif) Load </a></li> <li><a href="./image-load/">Image(png, jpeg, svg, ico, webp, avif) Load </a></li>
<li><a href="./usdz-load/">USDZ, USDA Load </a></li>
<li><a href="./ply-load/">PLY Load </a></li> <li><a href="./ply-load/">PLY Load </a></li>
<li><a href="./stl-load/">STL Load </a></li> <li><a href="./stl-load/">STL Load </a></li>
<li><a href="./ktx2-load/">KTX2 Load </a></li> <li><a href="./ktx2-load/">KTX2 Load </a></li>
<li><a href="./ktx-load/">KTX Load </a></li> <li><a href="./ktx-load/">KTX Load </a></li>
<li><a href="./extra-importer-plugins/">Extra(3ds, 3mf, collada, amf, bvh, vox, gcode, mdd, pcd, tilt, wrl, ldraw, vtk, xyz) Load </a></li>
</ul> </ul>
<h2 class="category">Export</h2> <h2 class="category">Export</h2>
<ul> <ul>
<h2 class="category">Animation</h2> <h2 class="category">Animation</h2>
<ul> <ul>
<li><a href="./gltf-animation-plugin/">glTF Animation Plugin </a></li> <li><a href="./gltf-animation-plugin/">glTF Animation Plugin </a></li>
<li><a href="./gltf-animation-plugin/">Popmotion Plugin </a></li>
<li><a href="./popmotion-plugin/">Popmotion Plugin </a></li>
<li><a href="./gltf-camera-animation/">glTF Camera Animation </a></li> <li><a href="./gltf-camera-animation/">glTF Camera Animation </a></li>
<li><a href="./gltf-animation-page-scroll/">glTF Animation Page Scroll </a></li> <li><a href="./gltf-animation-page-scroll/">glTF Animation Page Scroll </a></li>
</ul> </ul>
<h2 class="category">Utils</h2> <h2 class="category">Utils</h2>
<ul> <ul>
<li><a href="./render-target-preview/">Render Target Preview Plugin </a></li> <li><a href="./render-target-preview/">Render Target Preview Plugin </a></li>
<li><a href="./geometry-uv-preview/">Geometry UV Preview Plugin </a></li>
<li><a href="./parallel-asset-import/">Parallel Asset Import </a></li> <li><a href="./parallel-asset-import/">Parallel Asset Import </a></li>
<li><a href="./obj-to-glb/">Convert OBJ to GLB </a></li> <li><a href="./obj-to-glb/">Convert OBJ to GLB </a></li>
<li><a href="./3dm-to-glb/">Convert 3DM to GLB </a></li> <li><a href="./3dm-to-glb/">Convert 3DM to GLB </a></li>

+ 1
- 0
examples/ktx-load/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>KTX Texture Load</title> <title>KTX Texture Load</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/ktx2-load/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>KTX2 Texture Load</title> <title>KTX2 Texture Load</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/material-uiconfig/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Material UiConfig</title> <title>Material UiConfig</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/normal-buffer-plugin/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Depth Buffer Plugin</title> <title>Depth Buffer Plugin</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/obj-mtl-load/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>OBJ MTL Load</title> <title>OBJ MTL Load</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/obj-to-glb/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>OBJ To GLB</title> <title>OBJ To GLB</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/object-uiconfig/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Object UiConfig</title> <title>Object UiConfig</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/parallel-asset-import/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Parallel Asset Import/Download</title> <title>Parallel Asset Import/Download</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/ply-load/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>PLY Load</title> <title>PLY Load</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/pmat-material-export/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>PMAT(Physical) Material export</title> <title>PMAT(Physical) Material export</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/popmotion-plugin/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Popmotion Plugin</title> <title>Popmotion Plugin</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/progressive-plugin/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Progressive Plugin</title> <title>Progressive Plugin</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/render-target-export/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Image Snapshot Export</title> <title>Image Snapshot Export</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/render-target-preview/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Render Target Preview</title> <title>Render Target Preview</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/rhino3dm-load/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Rhino 3DM Load</title> <title>Rhino 3DM Load</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/scene-uiconfig/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Scene UiConfig</title> <title>Scene UiConfig</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/sphere-half-float-test/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Half float render pipeline test</title> <title>Half float render pipeline test</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/sphere-msaa-test/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>MSAA Test</title> <title>MSAA Test</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/sphere-rgbm-test/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>RGBM Render pipeline test</title> <title>RGBM Render pipeline test</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/stl-load/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>STL Load</title> <title>STL Load</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/tonemap-plugin/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Tonemap Plugin</title> <title>Tonemap Plugin</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 4
- 1
examples/tweakpane-editor/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Tweakpane Editor</title> <title>Tweakpane Editor</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>
<script type="importmap"> <script type="importmap">
{ {
"imports": { "imports": {
"three": "./../../dist/index.mjs",
"threepipe": "./../../dist/index.mjs", "threepipe": "./../../dist/index.mjs",
"@threepipe/plugin-tweakpane": "./../../plugins/tweakpane/dist/index.mjs", "@threepipe/plugin-tweakpane": "./../../plugins/tweakpane/dist/index.mjs",
"@threepipe/plugin-tweakpane-editor": "./../../plugins/tweakpane-editor/dist/index.mjs"
"@threepipe/plugin-tweakpane-editor": "./../../plugins/tweakpane-editor/dist/index.mjs",
"@threepipe/plugin-extra-importers": "./../../plugins/extra-importers/dist/index.mjs"
} }
} }



+ 9
- 5
examples/tweakpane-editor/script.ts Wyświetl plik

STLLoadPlugin, STLLoadPlugin,
ThreeViewer, ThreeViewer,
TonemapPlugin, TonemapPlugin,
USDZLoadPlugin,
ViewerUiConfigPlugin, ViewerUiConfigPlugin,
} from 'threepipe' } from 'threepipe'
import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane' import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane'
import {TweakpaneEditorPlugin} from '@threepipe/plugin-tweakpane-editor' import {TweakpaneEditorPlugin} from '@threepipe/plugin-tweakpane-editor'
import {extraImportPlugins} from '@threepipe/plugin-extra-importers'


async function init() { async function init() {


new NormalBufferPlugin(HalfFloatType, false), new NormalBufferPlugin(HalfFloatType, false),
new RenderTargetPreviewPlugin(false), new RenderTargetPreviewPlugin(false),
new FrameFadePlugin(), new FrameFadePlugin(),
new KTX2LoadPlugin(),
new KTXLoadPlugin(),
new PLYLoadPlugin(),
new Rhino3dmLoadPlugin(),
new STLLoadPlugin(),
KTX2LoadPlugin,
KTXLoadPlugin,
PLYLoadPlugin,
Rhino3dmLoadPlugin,
STLLoadPlugin,
USDZLoadPlugin,
...extraImportPlugins,
]) ])


const rt = viewer.getOrAddPluginSync(RenderTargetPreviewPlugin) const rt = viewer.getOrAddPluginSync(RenderTargetPreviewPlugin)

+ 1
- 0
examples/uint8-rgbm-hdr-test/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Uint8 RGBM HDR Test</title> <title>Uint8 RGBM HDR Test</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 35
- 0
examples/usdz-load/index.html Wyświetl plik

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>USDZ / USDA Load</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": {
"threepipe": "./../../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>

+ 31
- 0
examples/usdz-load/script.ts Wyświetl plik

import {_testFinish, IObject3D, ThreeViewer, USDZLoadPlugin} from 'threepipe'

async function init() {

const viewer = new ThreeViewer({
canvas: document.getElementById('mcanvas') as HTMLCanvasElement,
msaa: true,
dropzone: {
allowedExtensions: ['usdz', 'usda', 'hdr', 'exr'],
addOptions: {
disposeSceneObjects: true,
autoSetEnvironment: true, // when hdr is dropped
autoSetBackground: true,
},
},
})

viewer.addPluginSync(USDZLoadPlugin)

const options = {
autoCenter: true,
autoScale: true,
}
await Promise.all([
viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr'),
viewer.load<IObject3D>('https://threejs.org/examples/models/usdz/saeukkang.usdz', options),
])

}

init().then(_testFinish)

+ 1
- 0
examples/viewer-uiconfig/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Viewer UiConfig</title> <title>Viewer UiConfig</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 1
- 0
examples/z-prepass/index.html Wyświetl plik

<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Z-Prepass test</title> <title>Z-Prepass test</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill --> <!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported --> <!-- 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 async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

+ 8
- 8
package-lock.json Wyświetl plik

{ {
"name": "threepipe", "name": "threepipe",
"version": "0.0.12",
"version": "0.0.14",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "threepipe", "name": "threepipe",
"version": "0.0.12",
"version": "0.0.14",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1012/package.tgz",
"@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1014/package.tgz",
"@types/webxr": "^0.5.1", "@types/webxr": "^0.5.1",
"@types/wicg-file-system-access": "^2020.9.5", "@types/wicg-file-system-access": "^2020.9.5",
"ts-browser-helpers": "^0.8.0" "ts-browser-helpers": "^0.8.0"
"dev": true "dev": true
}, },
"node_modules/@types/three": { "node_modules/@types/three": {
"version": "0.152.1012",
"resolved": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1012/package.tgz",
"integrity": "sha512-G3Hyma5qGM+Wc1F2dapnIrdNY2uPr33eNYMzaDPbrvHJMHmoZyshrrl9tAodVpND+BVxXSvGiXpfunRGYPOtJg==",
"version": "0.152.1014",
"resolved": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1014/package.tgz",
"integrity": "sha512-1sR9iALwIFtfSXxJshAglvMjLy5litWF2hTbh0JQ+44d+21D2t0nppRZBnWtNQP5XsBYdhCNygnDQNeF6kd+NQ==",
"dependencies": { "dependencies": {
"@tweenjs/tween.js": "~18.6.4", "@tweenjs/tween.js": "~18.6.4",
"fflate": "~0.6.9", "fflate": "~0.6.9",
"dev": true "dev": true
}, },
"@types/three": { "@types/three": {
"version": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1012/package.tgz",
"integrity": "sha512-G3Hyma5qGM+Wc1F2dapnIrdNY2uPr33eNYMzaDPbrvHJMHmoZyshrrl9tAodVpND+BVxXSvGiXpfunRGYPOtJg==",
"version": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1014/package.tgz",
"integrity": "sha512-1sR9iALwIFtfSXxJshAglvMjLy5litWF2hTbh0JQ+44d+21D2t0nppRZBnWtNQP5XsBYdhCNygnDQNeF6kd+NQ==",
"requires": { "requires": {
"@tweenjs/tween.js": "~18.6.4", "@tweenjs/tween.js": "~18.6.4",
"fflate": "~0.6.9", "fflate": "~0.6.9",

+ 4
- 4
package.json Wyświetl plik

{ {
"name": "threepipe", "name": "threepipe",
"version": "0.0.12",
"version": "0.0.13",
"description": "A 3D viewer framework built on top of three.js in TypeScript with a focus on quality rendering, modularity and extensibility.", "description": "A 3D viewer framework built on top of three.js in TypeScript with a focus on quality rendering, modularity and extensibility.",
"main": "src/index.ts", "main": "src/index.ts",
"module": "dist/index.mjs", "module": "dist/index.mjs",
"popmotion": "^11.0.5" "popmotion": "^11.0.5"
}, },
"dependencies": { "dependencies": {
"@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1012/package.tgz",
"@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1014/package.tgz",
"@types/webxr": "^0.5.1", "@types/webxr": "^0.5.1",
"@types/wicg-file-system-access": "^2020.9.5", "@types/wicg-file-system-access": "^2020.9.5",
"ts-browser-helpers": "^0.8.0" "ts-browser-helpers": "^0.8.0"
"ts-browser-helpers": "^0.8.0", "ts-browser-helpers": "^0.8.0",
"three": "https://github.com/repalash/three.js-modded/releases/download/v0.152.2012/package.tgz", "three": "https://github.com/repalash/three.js-modded/releases/download/v0.152.2012/package.tgz",
"three-f": "https://github.com/repalash/three.js-modded/archive/refs/tags/v0.152.2012.tar.gz", "three-f": "https://github.com/repalash/three.js-modded/archive/refs/tags/v0.152.2012.tar.gz",
"@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1012/package.tgz",
"@types/three-f": "https://github.com/repalash/three-ts-types/archive/refs/tags/v0.152.1012.tar.gz",
"@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1014/package.tgz",
"@types/three-f": "https://github.com/repalash/three-ts-types/archive/refs/tags/v0.152.1014.tar.gz",
"@types/three-pkg": "https://gitpkg.now.sh/repalash/three-ts-types/types/three?modded_three" "@types/three-pkg": "https://gitpkg.now.sh/repalash/three-ts-types/types/three?modded_three"
}, },
"local_dependencies": { "local_dependencies": {

+ 30
- 0
plugins/extra-importers/package-lock.json Wyświetl plik

{
"name": "@threepipe/plugins-extra-importers",
"version": "0.1.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@threepipe/plugins-extra-importers",
"version": "0.1.0",
"license": "Apache-2.0",
"dependencies": {
"threepipe": "file:./../../src/"
},
"devDependencies": {}
},
"../../src": {},
"../tweakpane/src": {
"extraneous": true
},
"node_modules/threepipe": {
"resolved": "../../src",
"link": true
}
},
"dependencies": {
"threepipe": {
"version": "file:../../src"
}
}
}

+ 58
- 0
plugins/extra-importers/package.json Wyświetl plik

{
"name": "@threepipe/plugins-extra-importers",
"description": "Extra Threepipe plugins for importing several file types.",
"version": "0.1.0",
"devDependencies": {
},
"dependencies": {
"threepipe": "file:./../../src/"
},
"clean-package": {
"remove": [
"clean-package",
"scripts",
"devDependencies",
"//",
"markdown-to-html"
],
"replace": {
"dependencies": {
"threepipe": "^0.0.14"
}
}
},
"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"
}
}

+ 97
- 0
plugins/extra-importers/rollup.config.mjs Wyświetl plik

// 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 'path'
import {fileURLToPath} from '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({
// If you would like DEV messages, specify 'development'
// Otherwise use 'production'
'process.env.NODE_ENV': JSON.stringify('production') // for tippy.js
}),
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.
},
})
]
}

+ 36
- 0
plugins/extra-importers/src/global.d.ts Wyświetl plik

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

+ 244
- 0
plugins/extra-importers/src/index.ts Wyświetl plik

import {
AnyOptions,
BaseImporterPlugin,
BoxGeometry,
BufferGeometry,
Color,
Group,
ILoader,
Importer,
Mesh,
Object3D,
PhysicalMaterial,
Points,
PointsMaterial,
Scene,
SkeletonHelper,
} from 'threepipe'
import {TDSLoader} from 'three/examples/jsm/loaders/TDSLoader.js'
import {ThreeMFLoader} from 'three/examples/jsm/loaders/3MFLoader.js'
import {Collada, ColladaLoader} from 'three/examples/jsm/loaders/ColladaLoader.js'
import {AMFLoader} from 'three/examples/jsm/loaders/AMFLoader.js'
import {GCodeLoader} from 'three/examples/jsm/loaders/GCodeLoader.js'
import {BVH, BVHLoader} from 'three/examples/jsm/loaders/BVHLoader.js'
import {Chunk, VOXLoader, VOXMesh} from 'three/examples/jsm/loaders/VOXLoader.js'
import {MDD, MDDLoader} from 'three/examples/jsm/loaders/MDDLoader.js'
import {PCDLoader} from 'three/examples/jsm/loaders/PCDLoader.js'
import {TiltLoader} from 'three/examples/jsm/loaders/TiltLoader.js'
import {VRMLLoader} from 'three/examples/jsm/loaders/VRMLLoader.js'
import {LDrawLoader} from 'three/examples/jsm/loaders/LDrawLoader.js'
import {VTKLoader} from 'three/examples/jsm/loaders/VTKLoader.js'
import {XYZLoader} from 'three/examples/jsm/loaders/XYZLoader.js'

// 3ds
/**
* Adds support for loading Autodesk 3ds `.3ds`, `application/x-3ds` files and data uris
*/
export class TDSLoadPlugin extends BaseImporterPlugin {
public static readonly PluginType = 'TDSLoadPlugin'
protected _importer = new Importer(TDSLoader, ['3ds'], ['image/x-3ds', 'application/x-3ds'], false)
}

// 3mf
/**
* Adds support for loading `.3mf`, `model/3mf` files and data uris
*/
export class ThreeMFLoadPlugin extends BaseImporterPlugin {
public static readonly PluginType = 'ThreeMFLoadPlugin'
protected _importer = new Importer(ThreeMFLoader, ['3mf'], ['model/3mf'], false)
}

// collada
/**
* Adds support for loading Collada `.dae`, `model/vnd.collada+xml` files and data uris
*/
export class ColladaLoadPlugin extends BaseImporterPlugin {
public static readonly PluginType = 'ColladaLoadPlugin'
protected _importer = new Importer(class extends ColladaLoader implements ILoader {
transform(res: Collada, _: AnyOptions): Scene {
res.scene.userData.kinematics = res.kinematics
res.scene.userData.library = res.library
return res.scene
}
}, ['dae'], ['model/vnd.collada+xml'], false)
}

// amf
/**
* Adds support for loading Additive Manufacturing files `.amf`, `application/amf` files and data uris
*/
export class AMFLoadPlugin extends BaseImporterPlugin {
public static readonly PluginType = 'AMFLoadPlugin'
protected _importer = new Importer(AMFLoader, ['amf'], ['application/amf'], false)
}

// gcode
/**
* Adds support for loading `.gcode`, `application/gcode` files and data uris
*/
export class GCodeLoadPlugin extends BaseImporterPlugin {
public static readonly PluginType = 'GCodeLoadPlugin'
protected _importer = new Importer(GCodeLoader, ['gcode'], ['application/gcode'], false)
}

// bvh
/**
* Adds support for loading `.bvh`, `application/bvh` files and data uris
*/
export class BVHLoadPlugin extends BaseImporterPlugin {
public static readonly PluginType = 'BVHLoadPlugin'
protected _importer = new Importer(class extends BVHLoader implements ILoader {
transform(res: BVH, _: AnyOptions): Object3D {
const obj = new Object3D()
const helper = new SkeletonHelper(res.skeleton.bones[0])
obj.add(res.skeleton.bones[0])
obj.add(helper)
obj.animations = [res.clip]
obj.scale.set(0.1, 0.1, 0.1) // todo: autoScale and autoCenter not working
return obj
}
}, ['bvh'], ['application/bvh'], false)
}

// vox
/**
* Adds support for loading Magica Voxel `.vox` files and data uris
*/
export class VOXLoadPlugin extends BaseImporterPlugin {
public static readonly PluginType = 'VOXLoadPlugin'
protected _importer = new Importer(class extends VOXLoader implements ILoader {
transform(chunks: Chunk[], _: AnyOptions): Object3D {
const obj = new Object3D()
for (const chunk of chunks) {
// displayPalette( chunk.palette );
const mesh = new VOXMesh(chunk)
mesh.scale.setScalar(0.0015)
obj.add(mesh)
}
return obj
}
}, ['vox'], [''], false)
}


// mdd
/**
* Adds support for loading animation `.mdd`, `application/mdd` files and data uris
*/
export class MDDLoadPlugin extends BaseImporterPlugin {
public static readonly PluginType = 'MDDLoadPlugin'
protected _importer = new Importer(class extends MDDLoader implements ILoader {
transform(res: MDD, _: AnyOptions): Object3D {
const morphTargets = res.morphTargets
const geometry = new BoxGeometry()
geometry.morphAttributes.position = morphTargets // apply morph targets
const mesh = new Mesh(geometry, new PhysicalMaterial())
const obj = new Object3D()
obj.add(mesh)
res.clip.tracks.forEach(track=> track.name = mesh.uuid + track.name)
obj.animations = [res.clip]
return obj
}
}, ['mdd'], ['application/mdd'], false)
}

// pcd
/**
* Adds support for loading Point cloud data `.pcd`, `application/pcd` files and data uris
*/
export class PCDLoadPlugin extends BaseImporterPlugin {
public static readonly PluginType = 'PCDLoadPlugin'
protected _importer = new Importer(class extends PCDLoader implements ILoader {
transform(points: Points, options: AnyOptions): any {
if (options.autoCenter) points.geometry.center()
points.geometry.rotateX(Math.PI)
return points
}
}, ['pcd'], ['application/pcd'], false)
}

// tilt
/**
* Adds support for loading Tilt brush `.tilt`, `application/tilt` files and data uris
*/
export class TiltLoadPlugin extends BaseImporterPlugin {
public static readonly PluginType = 'TiltLoadPlugin'
protected _importer = new Importer(TiltLoader, ['tilt'], ['application/tilt'], false)
}

// vrml
/**
* Adds support for loading VRML `.wrl`, `model/vrml` files and data uris
*/
export class VRMLLoadPlugin extends BaseImporterPlugin {
public static readonly PluginType = 'VRMLLoadPlugin'
protected _importer = new Importer(VRMLLoader, ['wrl'], ['model/vrml'], false)
}

// ldraw
/**
* Adds support for loading LDraw `.mpd`, `application/mpd` files and data uris. see https://ldraw.org
*/
export class LDrawLoadPlugin extends BaseImporterPlugin {
public static readonly PluginType = 'LDrawLoadPlugin'
protected _importer = new Importer(class extends LDrawLoader implements ILoader {
transform(res: Group, _: AnyOptions): any {
// Convert from LDraw coordinates: rotate 180 degrees around OX
res.rotation.x = Math.PI
return res
}
}, ['mpd'], ['application/ldraw'], false)
}

// vtk
/**
* Adds support for loading VTK `.vtk`, '.vtp', `application/vtk` files and data uris
**/
export class VTKLoadPlugin extends BaseImporterPlugin {
public static readonly PluginType = 'VTKLoadPlugin'
protected _importer = new Importer(class extends VTKLoader implements ILoader {
transform(res: BufferGeometry, _: AnyOptions): Mesh|undefined {
if (!res.attributes?.normal) res.computeVertexNormals()
// todo set mesh name from options/path
return res ? new Mesh(res, new PhysicalMaterial({
color: new Color(1, 1, 1),
vertexColors: res.hasAttribute('color'),
})) : undefined
}
}, ['vtk', 'vtp'], ['application/vtk'], false)
}

// xyz
/**
* Adds support for loading XYZ `.xyz`, `text/plain+xyz` files and data uris
*/
export class XYZLoadPlugin extends BaseImporterPlugin {
public static readonly PluginType = 'XYZLoadPlugin'
protected _importer = new Importer(class extends XYZLoader implements ILoader {
transform(res: BufferGeometry, options: AnyOptions): Points|undefined {
if (!res.attributes?.normal) res.computeVertexNormals()
if (options.autoCenter) res.center()
return res ? new Points(res, new PointsMaterial({
size: 0.1,
vertexColors: res.hasAttribute('color'),
})) : undefined
}
}, ['xyz'], ['text/plain+xyz'], false)
}

export const extraImportPlugins = [
TDSLoadPlugin,
ThreeMFLoadPlugin,
ColladaLoadPlugin,
AMFLoadPlugin,
GCodeLoadPlugin,
BVHLoadPlugin,
VOXLoadPlugin,
MDDLoadPlugin,
PCDLoadPlugin,
TiltLoadPlugin,
VRMLLoadPlugin,
LDrawLoadPlugin,
VTKLoadPlugin,
XYZLoadPlugin,
] as const

+ 41
- 0
plugins/extra-importers/tsconfig.json Wyświetl plik

{
"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"
]
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"**/*.spec.ts",
"dist"
]
}

+ 10
- 0
plugins/extra-importers/typedoc.json Wyświetl plik

{
"extends": [
"../../typedoc.json"
],
"entryPoints": [
"src/index.ts"
],
"name": "Threepipe Extra Importer Plugins",
"readme": "none"
}

+ 36
- 0
plugins/plugin-template-rollup/package-lock.json Wyświetl plik

{
"name": "threepipe-plugin-template-rollup",
"version": "0.0.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "threepipe-plugin-template-rollup",
"version": "0.0.1",
"license": "Apache-2.0",
"dependencies": {
"@threepipe/plugin-tweakpane": "file:./../tweakpane/src/",
"threepipe": "file:./../../src/"
},
"devDependencies": {}
},
"../../src": {},
"../tweakpane/src": {},
"node_modules/@threepipe/plugin-tweakpane": {
"resolved": "../tweakpane/src",
"link": true
},
"node_modules/threepipe": {
"resolved": "../../src",
"link": true
}
},
"dependencies": {
"@threepipe/plugin-tweakpane": {
"version": "file:../tweakpane/src"
},
"threepipe": {
"version": "file:../../src"
}
}
}

+ 60
- 0
plugins/plugin-template-rollup/package.json Wyświetl plik

{
"name": "threepipe-plugin-template-rollup",
"description": "Sample Threepipe plugin using rollup",
"version": "0.1.0",
"devDependencies": {
},
"dependencies": {
"threepipe": "file:./../../src/",
"@threepipe/plugin-tweakpane": "file:./../tweakpane/src/"
},
"clean-package": {
"remove": [
"clean-package",
"scripts",
"devDependencies",
"//",
"markdown-to-html"
],
"replace": {
"dependencies": {
"threepipe": "^0.0.8",
"@threepipe/plugin-tweakpane": "^0.1.2"
}
}
},
"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"
}
}

+ 97
- 0
plugins/plugin-template-rollup/rollup.config.mjs Wyświetl plik

// 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 'path'
import {fileURLToPath} from '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",
"@threepipe/plugin-tweakpane": "@threepipe/plugin-tweakpane"
},
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({
// If you would like DEV messages, specify 'development'
// Otherwise use 'production'
'process.env.NODE_ENV': JSON.stringify('production') // for tippy.js
}),
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.
},
})
]
}

+ 3
- 0
plugins/plugin-template-rollup/src/SamplePlugin.css Wyświetl plik

html{

}

+ 19
- 0
plugins/plugin-template-rollup/src/SamplePlugin.ts Wyświetl plik

import {AViewerPluginSync, createStyles, ThreeViewer,} from 'threepipe'
import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane'
import styles from './SamplePlugin.css'

console.log(TweakpaneUiPlugin)

export class SamplePlugin extends AViewerPluginSync<string> {
public static readonly PluginType: string = 'SamplePlugin'
enabled = true
dependencies = []

constructor() {
super()
}
onAdded(viewer: ThreeViewer) {
super.onAdded(viewer)
createStyles(styles)
}
}

+ 36
- 0
plugins/plugin-template-rollup/src/global.d.ts Wyświetl plik

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

+ 1
- 0
plugins/plugin-template-rollup/src/index.ts Wyświetl plik

export {SamplePlugin} from './SamplePlugin'

+ 41
- 0
plugins/plugin-template-rollup/tsconfig.json Wyświetl plik

{
"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"
]
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"**/*.spec.ts",
"dist"
]
}

+ 10
- 0
plugins/plugin-template-rollup/typedoc.json Wyświetl plik

{
"extends": [
"../../typedoc.json"
],
"entryPoints": [
"src/index.ts"
],
"name": "Threepipe Tweakpane Editor Plugin",
"readme": "none"
}

+ 3
- 1
plugins/tweakpane/src/tpImageInputGenerator.ts Wyświetl plik

import { import {
CustomContextMenu, CustomContextMenu,
DataTexture,
EXRExporter2, EXRExporter2,
FloatType, FloatType,
generateUUID, generateUUID,
} from 'threepipe' } from 'threepipe'
import type {UiObjectConfig} from 'uiconfig.js' import type {UiObjectConfig} from 'uiconfig.js'
import {TweakpaneUiPlugin} from './TweakpaneUiPlugin' import {TweakpaneUiPlugin} from './TweakpaneUiPlugin'
import {DataTexture} from 'three'


const staticData = { const staticData = {
placeholderVal: 'placeholder', placeholderVal: 'placeholder',
// } // }
if (cc.isTexture) { if (cc.isTexture) {
// console.warn('here') // console.warn('here')
// todo: use textureToCanvas for data texture
if (cc.image && !cc.image.tp_src) { if (cc.image && !cc.image.tp_src) {
if (cc.image instanceof ImageBitmap || cc.image instanceof HTMLImageElement || cc.image instanceof HTMLVideoElement) { // todo: support playback in video if (cc.image instanceof ImageBitmap || cc.image instanceof HTMLImageElement || cc.image instanceof HTMLVideoElement) { // todo: support playback in video
cc.image.tp_src = imageBitmapToBase64(cc.image, 160) cc.image.tp_src = imageBitmapToBase64(cc.image, 160)
// data texture // data texture
if (!src && tex.isDataTexture) { if (!src && tex.isDataTexture) {
if (tex.type !== HalfFloatType && tex.type !== FloatType) { if (tex.type !== HalfFloatType && tex.type !== FloatType) {
// todo: use textureToCanvas for data texture
console.error('Only Float and HalfFloat Data texture export is supported', vcv, tex, config) console.error('Only Float and HalfFloat Data texture export is supported', vcv, tex, config)
return return
} }

+ 4
- 3
scripts/utils.mjs Wyświetl plik

const pluginDir = path.join(pluginsDir, pluginFolder) const pluginDir = path.join(pluginsDir, pluginFolder)
const packageJsonPath = path.join(pluginDir, 'package.json') const packageJsonPath = path.join(pluginDir, 'package.json')
if (!fs.existsSync(packageJsonPath)) continue; if (!fs.existsSync(packageJsonPath)) continue;
callback(pluginDir)
callback(pluginDir, pluginFolder)
} }


} }


export function execEachPlugin(command){
loopPluginDirs((pluginDir) => {
export function execEachPlugin(command, templates = false){
loopPluginDirs((pluginDir, pluginFolder) => {
if(!templates && pluginFolder.startsWith('plugin-template-')) return;
console.log(`Executing ${command} in ${pluginDir}`) console.log(`Executing ${command} in ${pluginDir}`)
execSync(command, {cwd: pluginDir, stdio: 'inherit'}) execSync(command, {cwd: pluginDir, stdio: 'inherit'})
}) })

+ 4
- 1
src/assetmanager/AssetManager.ts Wyświetl plik

* @category Asset Manager * @category Asset Manager
*/ */
export class AssetManager extends EventDispatcher<BaseEvent&{data: ImportResult}, 'loadAsset'> { export class AssetManager extends EventDispatcher<BaseEvent&{data: ImportResult}, 'loadAsset'> {
static readonly PluginType = 'AssetManager'
readonly viewer: ThreeViewer readonly viewer: ThreeViewer
readonly importer: AssetImporter readonly importer: AssetImporter
readonly exporter: AssetExporter readonly exporter: AssetExporter
return this.viewer?.loadConfigResources(json, extraResources) return this.viewer?.loadConfigResources(json, extraResources)
} }


/**
* @deprecated not a plugin anymore
*/
static readonly PluginType = 'AssetManager'
// endregion // endregion
} }

+ 1
- 0
src/core/IRenderer.ts Wyświetl plik

rgbm?: boolean, rgbm?: boolean,
msaa?: boolean, msaa?: boolean,
depthBuffer?: boolean, depthBuffer?: boolean,
renderScale?: number,
} }


export interface IWebGLRenderer<TManager extends IRenderManager=IRenderManager> extends WebGLRenderer { export interface IWebGLRenderer<TManager extends IRenderManager=IRenderManager> extends WebGLRenderer {

+ 1
- 1
src/core/IScene.ts Wyświetl plik

// region deprecated // region deprecated


/** /**
* @deprecated use {@link IObject3D.getObjectByName} instead
@deprecated use {@link getObjectByName} instead
* @param name * @param name
* @param parent * @param parent
*/ */

+ 106
- 91
src/core/object/RootScene.ts Wyświetl plik

readonly modelRoot: IObject3D readonly modelRoot: IObject3D


@uiColor<RootScene>('Background Color', (s)=>({ @uiColor<RootScene>('Background Color', (s)=>({
onChange: ()=>s?._onBackgroundChange(),
onChange: ()=>s?.onBackgroundChange(),
})) }))
@serialize() @onChange2(RootScene.prototype._onBackgroundChange)
@serialize() @onChange2(RootScene.prototype.onBackgroundChange)
backgroundColor: Color | null = null // read in three.js WebGLBackground backgroundColor: Color | null = null // read in three.js WebGLBackground


@onChange2(RootScene.prototype._onBackgroundChange)
@onChange2(RootScene.prototype.onBackgroundChange)
@serialize() @uiImage('Background Image') @serialize() @uiImage('Background Image')
background: null | Color | ITexture | 'environment' = null background: null | Color | ITexture | 'environment' = null
/** /**
this.refreshUi?.() this.refreshUi?.()
} }


private _onBackgroundChange() {
onBackgroundChange() {
this.dispatchEvent({type: 'backgroundChanged', background: this.background, backgroundColor: this.backgroundColor}) this.dispatchEvent({type: 'backgroundChanged', background: this.background, backgroundColor: this.backgroundColor})
this.setDirty({refreshScene: true, geometryChanged: false}) this.setDirty({refreshScene: true, geometryChanged: false})
this.refreshUi?.() this.refreshUi?.()
return return
} }


/**
* Find objects by name exact match in the complete hierarchy.
* @param name - name
* @param parent - optional root node to start search from
* @returns Array of found objects
*/
public findObjectsByName(name: string, parent?: IObject3D): IObject3D[] {
const o: IObject3D[] = [];
(parent ?? this).traverse(object => {
if (object.name === name) o.push(object)
})
return o
}

/** /**
* Returns the bounding box of the scene model root. * Returns the bounding box of the scene model root.
* @param precise * @param precise
return this return this
} }


/**
* @deprecated
* Sets the camera pointing towards the object at a specific distance.
* @param rootObject - The object to point at.
* @param centerOffset - The distance offset from the object to point at.
* @param targetOffset - The distance offset for the target from the center of object to point at.
* @param options - Not used yet.
*/
resetCamera(rootObject:Object3D|undefined = undefined, centerOffset = new Vector3(1, 1, 1), targetOffset = new Vector3(0, 0, 0)): void {
if (this._mainCamera) {
this.matrixWorldNeedsUpdate = true
this.updateMatrixWorld(true)
const bounds = rootObject ? new Box3B().expandByObject(rootObject, true, true) : this.getBounds(true)
const center = bounds.getCenter(new Vector3())
const radius = bounds.getSize(new Vector3()).length() * 0.5

center.add(targetOffset.clone().multiplyScalar(radius))

this._mainCamera.position = new Vector3( // todo: for nested cameras?
center.x + centerOffset.x * radius,
center.y + centerOffset.y * radius,
center.z + centerOffset.z * radius,
)
this._mainCamera.target = center
// this.scene.mainCamera.controls?.targetOffset.set(0, 0, 0)
this.setDirty()
}

}

/** /**
* Serialize the scene properties * Serialize the scene properties
* @param meta * @param meta
super.addEventListener(type, listener) super.addEventListener(type, listener)
} }


/**
* Minimum Camera near plane
* @deprecated - use camera.userData.minNearPlane instead
*/
get minNearDistance(): number {
console.error('minNearDistance is deprecated. Use camera.userData.minNearPlane instead')
return this.mainCamera.userData.minNearPlane ?? 0.02
}
/**
* @deprecated - use camera.userData.minNearPlane instead
*/
set minNearDistance(value: number) {
console.error('minNearDistance is deprecated. Use camera.userData.minNearPlane instead')
if (this.mainCamera)
this.mainCamera.userData.minNearPlane = value
}


/**
* @deprecated
*/
get activeCamera(): ICamera {
console.error('activeCamera is deprecated. Use mainCamera instead.')
return this.mainCamera
}

/**
* @deprecated
*/
set activeCamera(camera: ICamera | undefined) {
console.error('activeCamera is deprecated. Use mainCamera instead.')
this.mainCamera = camera
}

/**
* Get the threejs scene object
* @deprecated
*/
get modelObject(): this {
return this as any
}




// region inherited type fixes // region inherited type fixes
// re-declaring from IObject3D because: https://github.com/microsoft/TypeScript/issues/16936 // re-declaring from IObject3D because: https://github.com/microsoft/TypeScript/issues/16936
// } // }




/**
* Find objects by name exact match in the complete hierarchy.
* @deprecated Use {@link getObjectByName} instead.
* @param name - name
* @param parent - optional root node to start search from
* @returns Array of found objects
*/
public findObjectsByName(name: string, parent?: IObject3D): IObject3D[] {
const o: IObject3D[] = [];
(parent ?? this).traverse(object => {
if (object.name === name) o.push(object)
})
return o
}

/**
* @deprecated
* Sets the camera pointing towards the object at a specific distance.
* @param rootObject - The object to point at.
* @param centerOffset - The distance offset from the object to point at.
* @param targetOffset - The distance offset for the target from the center of object to point at.
* @param options - Not used yet.
*/
resetCamera(rootObject:Object3D|undefined = undefined, centerOffset = new Vector3(1, 1, 1), targetOffset = new Vector3(0, 0, 0)): void {
if (this._mainCamera) {
this.matrixWorldNeedsUpdate = true
this.updateMatrixWorld(true)
const bounds = rootObject ? new Box3B().expandByObject(rootObject, true, true) : this.getBounds(true)
const center = bounds.getCenter(new Vector3())
const radius = bounds.getSize(new Vector3()).length() * 0.5

center.add(targetOffset.clone().multiplyScalar(radius))

this._mainCamera.position = new Vector3( // todo: for nested cameras?
center.x + centerOffset.x * radius,
center.y + centerOffset.y * radius,
center.z + centerOffset.z * radius,
)
this._mainCamera.target = center
// this.scene.mainCamera.controls?.targetOffset.set(0, 0, 0)
this.setDirty()
}

}


/**
* Minimum Camera near plane
* @deprecated - use camera.userData.minNearPlane instead
*/
get minNearDistance(): number {
console.error('minNearDistance is deprecated. Use camera.userData.minNearPlane instead')
return this.mainCamera.userData.minNearPlane ?? 0.02
}
/**
* @deprecated - use camera.userData.minNearPlane instead
*/
set minNearDistance(value: number) {
console.error('minNearDistance is deprecated. Use camera.userData.minNearPlane instead')
if (this.mainCamera)
this.mainCamera.userData.minNearPlane = value
}


/**
* @deprecated
*/
get activeCamera(): ICamera {
console.error('activeCamera is deprecated. Use mainCamera instead.')
return this.mainCamera
}

/**
* @deprecated
*/
set activeCamera(camera: ICamera | undefined) {
console.error('activeCamera is deprecated. Use mainCamera instead.')
this.mainCamera = camera
}

/**
* Get the threejs scene object
* @deprecated
*/
get modelObject(): this {
return this as any
}

/**
* @deprecated use {@link envMapIntensity} instead
*/
get environmentIntensity(): number {
return this.envMapIntensity
}

/**
* @deprecated use {@link envMapIntensity} instead
*/
set environmentIntensity(value: number) {
this.envMapIntensity = value
}

/** /**
* Add any processed scene object to the scene. * Add any processed scene object to the scene.
* @deprecated renamed to {@link addObject} * @deprecated renamed to {@link addObject}

+ 24
- 0
src/plugins/base/BaseImporterPlugin.ts Wyświetl plik

import {IViewerPluginSync, ThreeViewer} from '../../viewer'
import {Importer} from '../../assetmanager'

export abstract class BaseImporterPlugin implements IViewerPluginSync {
declare ['constructor']: typeof BaseImporterPlugin
public static readonly PluginType: string

protected abstract _importer: Importer

toJSON: any = null // disable serialization

onAdded(viewer: ThreeViewer) {
viewer.assetManager.importer.addImporter(this._importer)
}

onRemove(viewer: ThreeViewer) {
viewer.assetManager.importer.removeImporter(this._importer)
}

dispose() {
return
}

}

+ 6
- 10
src/plugins/import/KTX2LoadPlugin.ts Wyświetl plik

import {IViewerPluginSync, ThreeViewer} from '../../viewer'
import {ThreeViewer} from '../../viewer'
import {GLTFWriter2, ILoader, Importer, ImportResultExtras} from '../../assetmanager' import {GLTFWriter2, ILoader, Importer, ImportResultExtras} from '../../assetmanager'
import {KTX2Loader} from 'three/examples/jsm/loaders/KTX2Loader.js' import {KTX2Loader} from 'three/examples/jsm/loaders/KTX2Loader.js'
import {CompressedTexture} from 'three' import {CompressedTexture} from 'three'
import {serializeTextureInExtras} from '../../utils' import {serializeTextureInExtras} from '../../utils'
import {ITexture} from '../../core' import {ITexture} from '../../core'
import {BaseImporterPlugin} from '../base/BaseImporterPlugin'


/** /**
* Adds support for loading Compressed Textures of format `.ktx2`, `image/ktx2` files and data uris. * Adds support for loading Compressed Textures of format `.ktx2`, `image/ktx2` files and data uris.
* @category Plugins * @category Plugins
*/ */
export class KTX2LoadPlugin implements IViewerPluginSync {
declare ['constructor']: typeof KTX2LoadPlugin

export class KTX2LoadPlugin extends BaseImporterPlugin {
public static readonly PluginType = 'KTX2LoadPlugin' public static readonly PluginType = 'KTX2LoadPlugin'
private _importer = new Importer(KTX2Loader2, ['ktx2'], ['image/ktx2'], false)
protected _importer = new Importer(KTX2Loader2, ['ktx2'], ['image/ktx2'], false)


public static TRANSCODER_LIBRARY_PATH = 'https://cdn.jsdelivr.net/gh/BinomialLLC/basis_universal@1.16.4/webgl/transcoder/build/' public static TRANSCODER_LIBRARY_PATH = 'https://cdn.jsdelivr.net/gh/BinomialLLC/basis_universal@1.16.4/webgl/transcoder/build/'


this._importer.onCtor = (l: KTX2Loader2) => l this._importer.onCtor = (l: KTX2Loader2) => l
.setTranscoderPath(KTX2LoadPlugin.TRANSCODER_LIBRARY_PATH) .setTranscoderPath(KTX2LoadPlugin.TRANSCODER_LIBRARY_PATH)
.detectSupport(viewer.renderManager.renderer) .detectSupport(viewer.renderManager.renderer)
viewer.assetManager.importer.addImporter(this._importer)
super.onAdded(viewer)
viewer.assetManager.exporter.getExporter('gltf', 'glb')?.extensions?.push(glTFTextureBasisUExtensionExport) viewer.assetManager.exporter.getExporter('gltf', 'glb')?.extensions?.push(glTFTextureBasisUExtensionExport)
} }


onRemove(viewer: ThreeViewer) { onRemove(viewer: ThreeViewer) {
viewer.assetManager.importer.removeImporter(this._importer)
super.onRemove(viewer)
const exporter = viewer.assetManager.exporter.getExporter('gltf', 'glb') const exporter = viewer.assetManager.exporter.getExporter('gltf', 'glb')
const index = exporter?.extensions?.indexOf(glTFTextureBasisUExtensionExport) const index = exporter?.extensions?.indexOf(glTFTextureBasisUExtensionExport)
if (index !== undefined && index !== -1) exporter?.extensions?.splice(index, 1) if (index !== undefined && index !== -1) exporter?.extensions?.splice(index, 1)
} }


dispose() {
return
}


} }



+ 3
- 17
src/plugins/import/KTXLoadPlugin.ts Wyświetl plik

import {IViewerPluginSync, ThreeViewer} from '../../viewer'
import {Importer} from '../../assetmanager' import {Importer} from '../../assetmanager'
import {KTXLoader} from 'three/examples/jsm/loaders/KTXLoader.js' import {KTXLoader} from 'three/examples/jsm/loaders/KTXLoader.js'
import {BaseImporterPlugin} from '../base/BaseImporterPlugin'


/** /**
* Adds support for loading `.ktx`, `image/ktx` files and data uris. * Adds support for loading `.ktx`, `image/ktx` files and data uris.
* @category Plugins * @category Plugins
*/ */
export class KTXLoadPlugin implements IViewerPluginSync {
declare ['constructor']: typeof KTXLoadPlugin

export class KTXLoadPlugin extends BaseImporterPlugin {
public static readonly PluginType = 'KTXLoadPlugin' public static readonly PluginType = 'KTXLoadPlugin'
private _importer = new Importer(KTXLoader, ['ktx'], ['image/ktx'], false)

onAdded(viewer: ThreeViewer) {
viewer.assetManager.importer.addImporter(this._importer)
}

onRemove(viewer: ThreeViewer) {
viewer.assetManager.importer.removeImporter(this._importer)
}

dispose() {
return
}
protected _importer = new Importer(KTXLoader, ['ktx'], ['image/ktx'], false)


} }

+ 7
- 19
src/plugins/import/PLYLoadPlugin.ts Wyświetl plik

import {IViewerPluginSync, ThreeViewer} from '../../viewer'
import {ILoader, Importer} from '../../assetmanager' import {ILoader, Importer} from '../../assetmanager'
import {PLYLoader} from 'three/examples/jsm/loaders/PLYLoader.js' import {PLYLoader} from 'three/examples/jsm/loaders/PLYLoader.js'
import {AnyOptions} from 'ts-browser-helpers' import {AnyOptions} from 'ts-browser-helpers'
import {BufferGeometry, Color, Mesh} from 'three' import {BufferGeometry, Color, Mesh} from 'three'
import {PhysicalMaterial} from '../../core' import {PhysicalMaterial} from '../../core'
import {BaseImporterPlugin} from '../base/BaseImporterPlugin'


/** /**
* Adds support for loading `.ply`, `text/plain+ply` files and data uris * Adds support for loading `.ply`, `text/plain+ply` files and data uris
* @category Plugins * @category Plugins
*/ */
export class PLYLoadPlugin implements IViewerPluginSync {
declare ['constructor']: typeof PLYLoadPlugin

export class PLYLoadPlugin extends BaseImporterPlugin {
public static readonly PluginType = 'PLYLoadPlugin' public static readonly PluginType = 'PLYLoadPlugin'
private _importer = new Importer(class extends PLYLoader implements ILoader {
protected _importer = new Importer(class extends PLYLoader implements ILoader {
transform(res: BufferGeometry, _: AnyOptions): Mesh|undefined { transform(res: BufferGeometry, _: AnyOptions): Mesh|undefined {
if (!res.attributes?.normal) res.computeVertexNormals() if (!res.attributes?.normal) res.computeVertexNormals()
// todo set mesh name from options/path // todo set mesh name from options/path
return res ? new Mesh(res, new PhysicalMaterial({color: new Color(1, 1, 1)})) : undefined
return res ? new Mesh(res, new PhysicalMaterial({
color: new Color(1, 1, 1),
vertexColors: res.hasAttribute('color'),
})) : undefined
} }
}, ['ply'], ['text/plain+ply'], false) }, ['ply'], ['text/plain+ply'], false)

onAdded(viewer: ThreeViewer) {
viewer.assetManager.importer.addImporter(this._importer)
}

onRemove(viewer: ThreeViewer) {
viewer.assetManager.importer.removeImporter(this._importer)
}

dispose() {
return
}

} }

+ 3
- 18
src/plugins/import/Rhino3dmLoadPlugin.ts Wyświetl plik

import {IViewerPluginSync, ThreeViewer} from '../../viewer'
import {Importer, Rhino3dmLoader2} from '../../assetmanager' import {Importer, Rhino3dmLoader2} from '../../assetmanager'
import {BaseImporterPlugin} from '../base/BaseImporterPlugin'


/** /**
* Adds support for loading Rhino `.3dm`, `model/vnd.3dm`, `model/3dm` files and data uris. * Adds support for loading Rhino `.3dm`, `model/vnd.3dm`, `model/3dm` files and data uris.
* @category Plugins * @category Plugins
*/ */
export class Rhino3dmLoadPlugin implements IViewerPluginSync {
declare ['constructor']: typeof Rhino3dmLoadPlugin

export class Rhino3dmLoadPlugin extends BaseImporterPlugin {
public static readonly PluginType = 'Rhino3dmLoadPlugin' public static readonly PluginType = 'Rhino3dmLoadPlugin'
private _importer = new Importer(Rhino3dmLoader2, ['3dm'], ['model/vnd.3dm', 'model/3dm'], true)

onAdded(viewer: ThreeViewer) {
viewer.assetManager.importer.addImporter(this._importer)
}

onRemove(viewer: ThreeViewer) {
viewer.assetManager.importer.removeImporter(this._importer)
}

dispose() {
return
}

protected _importer = new Importer(Rhino3dmLoader2, ['3dm'], ['model/vnd.3dm', 'model/3dm'], true)
} }

+ 7
- 18
src/plugins/import/STLLoadPlugin.ts Wyświetl plik

import {IViewerPluginSync, ThreeViewer} from '../../viewer'
import {ILoader, Importer} from '../../assetmanager' import {ILoader, Importer} from '../../assetmanager'
import {STLLoader} from 'three/examples/jsm/loaders/STLLoader.js' import {STLLoader} from 'three/examples/jsm/loaders/STLLoader.js'
import {BufferGeometry, Color, Mesh} from 'three' import {BufferGeometry, Color, Mesh} from 'three'
import {AnyOptions} from 'ts-browser-helpers' import {AnyOptions} from 'ts-browser-helpers'
import {PhysicalMaterial} from '../../core' import {PhysicalMaterial} from '../../core'
import {BaseImporterPlugin} from '../base/BaseImporterPlugin'


/** /**
* Adds support for loading `.stl`, `model/stl` files and data uris. * Adds support for loading `.stl`, `model/stl` files and data uris.
* @category Plugins * @category Plugins
*/ */
export class STLLoadPlugin implements IViewerPluginSync {
declare ['constructor']: typeof STLLoadPlugin

export class STLLoadPlugin extends BaseImporterPlugin {
public static readonly PluginType = 'STLLoadPlugin' public static readonly PluginType = 'STLLoadPlugin'
private _importer = new Importer(class extends STLLoader implements ILoader {
protected _importer = new Importer(class extends STLLoader implements ILoader {
transform(res: BufferGeometry, _: AnyOptions): Mesh|undefined { transform(res: BufferGeometry, _: AnyOptions): Mesh|undefined {
if (!res.attributes?.normal) res.computeVertexNormals() if (!res.attributes?.normal) res.computeVertexNormals()
// todo set mesh name from options/path // todo set mesh name from options/path
return res ? new Mesh(res, new PhysicalMaterial({color: new Color(1, 1, 1)})) : undefined
return res ? new Mesh(res, new PhysicalMaterial({
color: new Color(1, 1, 1),
vertexColors: res.hasAttribute('color'),
})) : undefined
} }
}, ['stl'], ['model/stl', 'model/x.stl-binary', 'model/x.stl-ascii'], false) }, ['stl'], ['model/stl', 'model/x.stl-binary', 'model/x.stl-ascii'], false)


onAdded(viewer: ThreeViewer) {
viewer.assetManager.importer.addImporter(this._importer)
}

onRemove(viewer: ThreeViewer) {
viewer.assetManager.importer.removeImporter(this._importer)
}

dispose() {
return
}

} }

+ 38
- 0
src/plugins/import/USDZLoadPlugin.ts Wyświetl plik

import {Importer} from '../../assetmanager'
import {USDZLoader} from 'three/examples/jsm/loaders/USDZLoader.js'
import {Group, Mesh} from 'three'
import {Zippable, zipSync} from 'three/examples/jsm/libs/fflate.module.js'
import {BaseImporterPlugin} from '../base/BaseImporterPlugin'

/**
* Adds support for loading `.usdz`, `model/vnd.usd+zip` and `.usda`, `model/vnd.usda` files and data uris
* @category Plugins
*/
export class USDZLoadPlugin extends BaseImporterPlugin {
public static readonly PluginType = 'USDZLoadPlugin'
protected _importer = new Importer(class extends USDZLoader {

currentUrl = ''

async loadAsync(url: string, onProgress?: (event: ProgressEvent) => void): Promise<Mesh> {
this.currentUrl = url
const res = await super.loadAsync(url, onProgress)
this.currentUrl = ''
return res
}

parse(buffer: ArrayBuffer|string): Group {
// todo make changes in three.js to allow passing unzipped buffer directly for usda
if (this.currentUrl.endsWith('.usda') && typeof buffer !== 'string') {
const filename = this.currentUrl.split('/').pop()
if (filename) {
const zip: Zippable = {}
zip[filename] = new Uint8Array(buffer)
buffer = zipSync(zip).buffer
}
}
return super.parse(buffer)
}
}, ['usdz', 'usda'], ['model/vnd.usd+zip', 'model/vnd.usdz+zip', 'model/vnd.usda'], false)

}

+ 3
- 0
src/plugins/index.ts Wyświetl plik

// base // base
export {PipelinePassPlugin} from './base/PipelinePassPlugin' export {PipelinePassPlugin} from './base/PipelinePassPlugin'
export {BaseImporterPlugin} from './base/BaseImporterPlugin'


// pipeline // pipeline
export {ProgressivePlugin} from './pipeline/ProgressivePlugin' export {ProgressivePlugin} from './pipeline/ProgressivePlugin'


// ui // ui
export {RenderTargetPreviewPlugin} from './ui/RenderTargetPreviewPlugin' export {RenderTargetPreviewPlugin} from './ui/RenderTargetPreviewPlugin'
export {GeometryUVPreviewPlugin} from './ui/GeometryUVPreviewPlugin'
export {ViewerUiConfigPlugin} from './ui/ViewerUiConfigPlugin' export {ViewerUiConfigPlugin} from './ui/ViewerUiConfigPlugin'
export {SceneUiConfigPlugin} from './ui/SceneUiConfigPlugin' export {SceneUiConfigPlugin} from './ui/SceneUiConfigPlugin'




// import // import
export {Rhino3dmLoadPlugin} from './import/Rhino3dmLoadPlugin' export {Rhino3dmLoadPlugin} from './import/Rhino3dmLoadPlugin'
export {USDZLoadPlugin} from './import/USDZLoadPlugin'
export {PLYLoadPlugin} from './import/PLYLoadPlugin' export {PLYLoadPlugin} from './import/PLYLoadPlugin'
export {STLLoadPlugin} from './import/STLLoadPlugin' export {STLLoadPlugin} from './import/STLLoadPlugin'
export {KTXLoadPlugin} from './import/KTXLoadPlugin' export {KTXLoadPlugin} from './import/KTXLoadPlugin'

+ 49
- 0
src/plugins/ui/GeometryUVPreviewPlugin.css Wyświetl plik

#GeometryUVPreviewPluginContainer{
position: absolute;
left: 0;
bottom: 0;
width: 100%;
z-index: 1000;
display: flex;
flex-wrap: wrap;
flex-direction: row;
gap: 5px;
padding: 5px;
pointer-events: none;
height: auto;
}
.GeometryUVPreviewPluginTarget{
position: relative;
width: 200px;
height: 200px;
}
.GeometryUVPreviewPluginCollapsed{
height: 25px;
}
.GeometryUVPreviewPluginTargetHeader{
position: absolute;
top: 0;
left: 0;
right: 0;
background: rgba(0,0,0,0.5);
color: white;
padding: 2px;
font-size: 16px;
height: 20px;
font-family: monospace;
text-align: center;
pointer-events: auto;
cursor: pointer;
}
.GeometryUVPreviewPluginTargetHeader::after{
content: '-';
position: absolute;
right: 2px;
width: 20px;
height: 20px;
line-height: 16px;
}
.GeometryUVPreviewPluginCollapsed .GeometryUVPreviewPluginTargetHeader::after{
content: '+';
line-height: 20px;
}

+ 166
- 0
src/plugins/ui/GeometryUVPreviewPlugin.ts Wyświetl plik

import {AViewerPluginSync, ThreeViewer} from '../../viewer'
import {createDiv, createStyles, getOrCall, onChange, ValOrFunc} from 'ts-browser-helpers'
import styles from './GeometryUVPreviewPlugin.css'
import {CustomContextMenu} from '../../utils'
import {uiFolderContainer, uiToggle} from 'uiconfig.js'
import {IGeometry} from '../../core'
import {UVsDebug} from 'three/examples/jsm/utils/UVsDebug.js'

export interface TargetBlock {
target: ValOrFunc<IGeometry|undefined>
name: string
visible: boolean
div: HTMLDivElement
uvCanvas?: HTMLCanvasElement
}

@uiFolderContainer('Render Target Preview Plugin')
export class GeometryUVPreviewPlugin<TEvent extends string> extends AViewerPluginSync<TEvent> {
static readonly PluginType = 'GeometryUVPreviewPlugin'

@uiToggle('Enabled')
@onChange(GeometryUVPreviewPlugin.prototype.refreshUi) enabled = true
toJSON: any = null

mainDiv: HTMLDivElement = createDiv({id: 'GeometryUVPreviewPluginContainer', addToBody: false})
stylesheet?: HTMLStyleElement

constructor(enabled = true) {
super()
this.enabled = enabled
}

targetBlocks: TargetBlock[] = []

onAdded(viewer: ThreeViewer): void {
super.onAdded(viewer)

viewer.addEventListener('postRender', this._postRender)
this.stylesheet = createStyles(styles, viewer.container)
this.refreshUi()
}

onRemove(viewer: ThreeViewer): void {
viewer.removeEventListener('postRender', this._postRender)
this.stylesheet?.remove()
this.stylesheet = undefined
this.refreshUi()
super.onRemove(viewer)
}

private _postRender = () => {
if (!this._viewer) return

for (const target of this.targetBlocks) {
if (!target.visible) continue
const geo = getOrCall(target.target)
if (!geo?.attributes?.uv) {
// todo draw white or pink
continue
}
if (!target.uvCanvas) {
target.uvCanvas = UVsDebug(geo, 1024)
target.uvCanvas.style.width = '100%'
target.uvCanvas.style.height = '100%'
}
if (target.uvCanvas && target.uvCanvas.parentElement !== target.div) target.div.appendChild(target.uvCanvas)
// const rect = target.div.getBoundingClientRect()
// const canvasRect = this._viewer.canvas.getBoundingClientRect()
// rect.x = rect.x - canvasRect.x
// rect.y = canvasRect.height + canvasRect.y - rect.y - rect.height
// if (Array.isArray(tex)) {
// // todo support multi target
// this._viewer.console.warn('Multi target preview not supported yet')
// continue
// }
// const outputColorSpace = this._viewer.renderManager.webglRenderer.outputColorSpace
// if (!target.originalColorSpace) this._viewer.renderManager.webglRenderer.outputColorSpace = SRGBColorSpace
// this._viewer.renderManager.blit(null, {
// source: tex,
// clear: !target.transparent,
// respectColorSpace: !target.originalColorSpace,
// viewport: new Vector4(rect.x, rect.y, rect.width, rect.height),
// })
// this._viewer.renderManager.webglRenderer.outputColorSpace = outputColorSpace
}
}

addGeometry(target: ValOrFunc<IGeometry|undefined>, name: string, visible = true): this {
if (!target) return this
const div = document.createElement('div')
const targetDef: TargetBlock = {target, name, div, visible}
div.classList.add('GeometryUVPreviewPluginTarget')
if (!targetDef.visible) div.classList.add('GeometryUVPreviewPluginCollapsed')
const header = document.createElement('div')
header.classList.add('GeometryUVPreviewPluginTargetHeader')
header.innerText = name
header.onclick = () => {
targetDef.visible = !targetDef.visible
if (!targetDef.visible) div.classList.add('GeometryUVPreviewPluginCollapsed')
else div.classList.remove('GeometryUVPreviewPluginCollapsed')
this._viewer?.setDirty()
}
header.oncontextmenu = (e) => {
e.preventDefault()
e.stopPropagation()
CustomContextMenu.Create({
'Download': () => this.downloadGeometryUV(targetDef),
'Remove': () => this.removeGeometry(target),
}, e.clientX, e.clientY)
}
div.appendChild(header)
this.mainDiv.appendChild(div)
this.targetBlocks.push(targetDef)
this.refreshUi()
return this
}

removeGeometry(target: ValOrFunc<IGeometry|undefined>): this {
const index = this.targetBlocks.findIndex(t => t.target === target)
if (index >= 0) {
const t = this.targetBlocks[index]
this.targetBlocks.splice(index, 1)
t.div.remove()
}
this.refreshUi()
return this
}

downloadGeometryUV(targetDef: TargetBlock): this {
if (!this._viewer) return this
if (!targetDef.uvCanvas) return this
const canvas = targetDef.uvCanvas
const url = canvas.toDataURL('image/png')
const link = document.createElement('a')
document.body.appendChild(link)
link.style.display = 'none'
link.href = url
link.download = 'renderTarget.' + 'png'
link.click()
document.body.removeChild(link)
URL.revokeObjectURL(url)
return this
}

refreshUi(): void {
if (!this.mainDiv) return
if (!this._viewer) {
if (this.mainDiv.parentElement) this.mainDiv.remove()
this.mainDiv.style.display = 'none'
this.mainDiv.style.zIndex = '1000'
return
}
if (!this.mainDiv.parentElement) this._viewer.container?.appendChild(this.mainDiv)
this.mainDiv.style.display = this.enabled ? 'flex' : 'none'
this.mainDiv.style.zIndex = parseInt(this._viewer.canvas.style.zIndex || '0') + 1 + ''
this._viewer?.setDirty()
}

dispose() {
for (const target of this.targetBlocks) {
this.removeGeometry(target.target)
}
super.dispose()
}

}

+ 16
- 2
src/rendering/RenderManager.ts Wyświetl plik

this.dispatchEvent({type: 'animationLoop', deltaTime, time, renderer: this._renderer, xrFrame: frame}) this.dispatchEvent({type: 'animationLoop', deltaTime, time, renderer: this._renderer, xrFrame: frame})
} }


constructor({canvas, alpha = true, targetOptions}:IRenderManagerOptions) {
constructor({canvas, alpha = true, renderScale = 1, targetOptions}:IRenderManagerOptions) {
super() super()
this._animationLoop = this._animationLoop.bind(this) this._animationLoop = this._animationLoop.bind(this)
// this._xrPreAnimationLoop = this._xrPreAnimationLoop.bind(this) // this._xrPreAnimationLoop = this._xrPreAnimationLoop.bind(this)
this._renderSize = new Vector2(canvas.clientWidth, canvas.clientHeight) this._renderSize = new Vector2(canvas.clientWidth, canvas.clientHeight)
this._renderScale = renderScale
this._renderer = this._initWebGLRenderer(canvas, alpha) this._renderer = this._initWebGLRenderer(canvas, alpha)
this._context = this._renderer.getContext() this._context = this._renderer.getContext()
this._isWebGL2 = this._renderer.capabilities.isWebGL2 this._isWebGL2 = this._renderer.capabilities.isWebGL2
return this._context return this._context
} }


/**
* Same as {@link renderer}
*/
get webglRenderer(): WebGLRenderer { get webglRenderer(): WebGLRenderer {
return this._renderer return this._renderer
} }
// region Utils // region Utils


/** /**
*
* blit - blits a texture to the screen or another render target.
* @param destination - destination target, or screen if undefined or null * @param destination - destination target, or screen if undefined or null
* @param source - source Texture * @param source - source Texture
* @param viewport - viewport and scissor * @param viewport - viewport and scissor
return string return string
} }


/**
* Rend pixels from a render target into a new Uint8Array|Uint16Array|Float32Array buffer
* @param target
*/
renderTargetToBuffer(target: WebGLRenderTarget): Uint8Array|Uint16Array|Float32Array { renderTargetToBuffer(target: WebGLRenderTarget): Uint8Array|Uint16Array|Float32Array {
const buffer = const buffer =
target.texture.type === HalfFloatType ? target.texture.type === HalfFloatType ?
return buffer return buffer
} }


/**
* Exports a render target to a blob. The type is automatically picked from exr to png based on the render target.
* @param target - render target to export
* @param mimeType - mime type to use.
* If auto (default), then it will be picked based on the render target type.
*/
exportRenderTarget(target: WebGLRenderTarget, mimeType = 'auto'): BlobExt { exportRenderTarget(target: WebGLRenderTarget, mimeType = 'auto'): BlobExt {
const hdrFormats = ['image/x-exr'] const hdrFormats = ['image/x-exr']
let hdr = target.texture.type === HalfFloatType || target.texture.type === FloatType let hdr = target.texture.type === HalfFloatType || target.texture.type === FloatType

+ 34
- 1
src/utils/CustomContextMenu.ts Wyświetl plik

import styles from './CustomContextMenu.css' import styles from './CustomContextMenu.css'


/**
* Represents a custom context menu that can be created and managed dynamically.
*/
export class CustomContextMenu { export class CustomContextMenu {
/**
* The HTML element representing the context menu.
*/
public static Element: HTMLDivElement | undefined = undefined public static Element: HTMLDivElement | undefined = undefined

/**
* Indicates whether the context menu has been initialized.
*/
private static _inited = false private static _inited = false


/**
* Initializes the context menu by adding event listeners.
* This method should be called before creating a context menu.
*/
private static _initialize(): void { private static _initialize(): void {
this._inited = true this._inited = true
document.addEventListener('pointerdown', (e) => { document.addEventListener('pointerdown', (e) => {
}) })
} }


public static Create(items: Record<string, () => void>, x: number, y: number, show = true, removeOnSelect = true): HTMLDivElement {
/**
* Creates a custom context menu with specified items and options.
*
* @param items - An object containing menu item labels and corresponding callback functions.
* @param x - The horizontal position of the context menu.
* @param y - The vertical position of the context menu.
* @param show - Indicates whether the context menu should be displayed immediately.
* @param removeOnSelect - Indicates whether the context menu should be removed after an item is selected.
* @returns The HTML element representing the created context menu.
*/
public static Create(
items: Record<string, () => void>,
x: number,
y: number,
show = true,
removeOnSelect = true
): HTMLDivElement {
if (!this._inited) this._initialize() if (!this._inited) this._initialize()


if (this.Element) this.Remove() if (this.Element) this.Remove()
return container return container
} }


/**
* Removes the context menu from the DOM.
*/
public static Remove(): void { public static Remove(): void {
this.Element?.remove() this.Element?.remove()
this.Element = undefined this.Element = undefined

+ 1
- 0
src/utils/serialization.ts Wyświetl plik

if (res._context) delete res._context if (res._context) delete res._context
return res return res
} }

export function metaFromResources(resources?: Partial<SerializationResourcesType>, viewer?: ThreeViewer): SerializationMetaType { export function metaFromResources(resources?: Partial<SerializationResourcesType>, viewer?: ThreeViewer): SerializationMetaType {
return { return {
...resources, ...resources,

+ 9
- 0
src/utils/shader-helpers.ts Wyświetl plik

const warnEnabled = true const warnEnabled = true


/**
* Replace a string in a shader function with added options to prepend, append, show warning when not found, and replace all occurrences.
* @param shader - shader code
* @param str - string to replace
* @param newStr - new string to replace with
* @param replaceAll - replace all occurrences
* @param prepend - prepend new string to old string
* @param append - append new string to old string
*/
export function shaderReplaceString(shader: string, str: string, newStr: string, { export function shaderReplaceString(shader: string, str: string, newStr: string, {
replaceAll = false, replaceAll = false,
prepend = false, prepend = false,

+ 237
- 209
src/viewer/ThreeViewer.ts Wyświetl plik

*/ */
msaa?: boolean, msaa?: boolean,
/** /**
* Use RGBM HDR Pipeline
* Use Uint8 RGBM HDR Render Pipeline.
* Provides better performance with post-processing.
* RenderManager Uses Half-float if set to false.
*/ */
rgbm?: boolean rgbm?: boolean
/** /**
*/ */
zPrepass?: boolean zPrepass?: boolean


/*
* Render scale, 1 = full resolution, 0.5 = half resolution, 2 = double resolution.
* Same as pixelRatio in three.js
* Can be set to `window.devicePixelRatio` to render at device resolution in browsers.
* An optimal value is `Math.min(2, window.devicePixelRatio)` to prevent issues on mobile.
*/
renderScale?: number

debug?: boolean debug?: boolean


/** /**
} }
static Dialog: IDialogWrapper = windowDialogWrapper static Dialog: IDialogWrapper = windowDialogWrapper


renderStats: GLStatsJS

readonly assetManager: AssetManager

get console(): IConsoleWrapper {
return ThreeViewer.Console
}
get dialog(): IDialogWrapper {
return ThreeViewer.Dialog
}

@serialize() readonly type = 'ThreeViewer'

private readonly _canvas: HTMLCanvasElement

// this can be used by other plugins to add ui elements alongside the canvas
private readonly _container: HTMLElement // todo: add a way to move the canvas to a new container... and dispatch event...

@uiConfig() @serialize('renderManager')
readonly renderManager: ViewerRenderManager

/**
* The Scene attached to the viewer, this cannot be changed.
* @type {RootScene}
*/
@uiConfig() @serialize('scene')
private readonly _scene: RootScene

public readonly plugins: Record<string, IViewerPlugin> = {}
private _needsResize = false

/** /**
* If the viewer is enabled. Set this `false` to disable RAF loop. * If the viewer is enabled. Set this `false` to disable RAF loop.
* @type {boolean} * @type {boolean}
*/ */
enabled = true enabled = true


/** /**
* Enable or disable all rendering, Animation loop including any frame/render events won't be fired when this is false. * Enable or disable all rendering, Animation loop including any frame/render events won't be fired when this is false.
*/ */
@onChange(ThreeViewer.prototype._renderEnabledChanged) @onChange(ThreeViewer.prototype._renderEnabledChanged)
renderEnabled = true renderEnabled = true

private _isRenderingFrame = false

renderStats: GLStatsJS
readonly assetManager: AssetManager
@uiConfig() @serialize('renderManager')
readonly renderManager: ViewerRenderManager
public readonly plugins: Record<string, IViewerPlugin> = {}
/**
* Scene with object hierarchy used for rendering
*/
get scene(): RootScene {
return this._scene
}
/** /**
* Specifies how many frames to render in a single request animation frame. Keep to 1 for realtime rendering. * Specifies how many frames to render in a single request animation frame. Keep to 1 for realtime rendering.
* Note: should be max (screen refresh rate / animation frame rate) like 60Hz / 30fps * Note: should be max (screen refresh rate / animation frame rate) like 60Hz / 30fps
* @type {number} * @type {number}
*/ */
public maxFramePerLoop = 1 public maxFramePerLoop = 1
readonly debug: boolean


get scene(): RootScene {
return this._scene
/**
* Get the HTML Element containing the canvas
* @returns {HTMLElement}
*/
get container(): HTMLElement {
return this._container
}

/**
* Get the HTML Canvas Element where the viewer is rendering
* @returns {HTMLCanvasElement}
*/
get canvas(): HTMLCanvasElement {
return this._canvas
}

get console(): IConsoleWrapper {
return ThreeViewer.Console
} }
get dialog(): IDialogWrapper {
return ThreeViewer.Dialog
}
@serialize() readonly type = 'ThreeViewer'


/** /**
* The ResizeObserver observing the canvas element. Add more elements to this observer to resize viewer on their size change. * The ResizeObserver observing the canvas element. Add more elements to this observer to resize viewer on their size change.
*/ */
readonly resizeObserver = window?.ResizeObserver ? new window.ResizeObserver(_ => this.resize()) : undefined readonly resizeObserver = window?.ResizeObserver ? new window.ResizeObserver(_ => this.resize()) : undefined


private readonly _canvas: HTMLCanvasElement
// this can be used by other plugins to add ui elements alongside the canvas
private readonly _container: HTMLElement // todo: add a way to move the canvas to a new container... and dispatch event...
/**
* The Scene attached to the viewer, this cannot be changed.
* @type {RootScene}
*/
@uiConfig() @serialize('scene')
private readonly _scene: RootScene
private _needsResize = false
private _isRenderingFrame = false
private _objectProcessor: IObjectProcessor = {
processObject: (object: IObject3D)=>{
if (object.material) {
if (Array.isArray(object.material)) this.assetManager.materials.registerMaterials(object.material)
else this.assetManager.materials.registerMaterial(object.material)
}
},
}
private _needsReset = true // renderer needs reset

// Helpers for tracking main camera change and setting dirty automatically
private _lastCameraPosition: Vector3 = new Vector3() private _lastCameraPosition: Vector3 = new Vector3()
private _lastCameraQuat: Quaternion = new Quaternion() private _lastCameraQuat: Quaternion = new Quaternion()
private _lastCameraTarget: Vector3 = new Vector3() private _lastCameraTarget: Vector3 = new Vector3()
private _tempVec: Vector3 = new Vector3() private _tempVec: Vector3 = new Vector3()
private _tempQuat: Quaternion = new Quaternion() private _tempQuat: Quaternion = new Quaternion()


readonly debug: boolean
/** /**
* Create a viewer instance for using the webgi viewer SDK. * Create a viewer instance for using the webgi viewer SDK.
* @param options - {@link ThreeViewerOptions} * @param options - {@link ThreeViewerOptions}
zPrepass: options.zPrepass ?? options.useGBufferDepth ?? false, zPrepass: options.zPrepass ?? options.useGBufferDepth ?? false,
depthBuffer: !(options.zPrepass ?? options.useGBufferDepth ?? false), depthBuffer: !(options.zPrepass ?? options.useGBufferDepth ?? false),
screenShader: options.screenShader, screenShader: options.screenShader,
renderScale: options.renderScale,
}) })
this.renderManager.addEventListener('animationLoop', this._animationLoop as any) this.renderManager.addEventListener('animationLoop', this._animationLoop as any)
this.renderManager.addEventListener('resize', ()=> this._scene.mainCamera.refreshAspect()) this.renderManager.addEventListener('resize', ()=> this._scene.mainCamera.refreshAspect())


} }


private _objectProcessor: IObjectProcessor = {
processObject: (object: IObject3D)=>{
if (object.material) {
if (Array.isArray(object.material)) this.assetManager.materials.registerMaterials(object.material)
else this.assetManager.materials.registerMaterial(object.material)
}
},
}

// todo: find a better fix for context loss and restore?
private _lastSize = new Vector2()
private _onContextRestore = (_: Event) => {
this.enabled = true
this._canvas.width = this._lastSize.width
this._canvas.height = this._lastSize.height
this.resize()
this._scene.setDirty({refreshScene: true, frameFade: false})
}
private _onContextLost = (_: Event) => {
this._lastSize.set(this._canvas.width, this._canvas.height)
this._canvas.width = 2
this._canvas.height = 2
this.resize()
this.enabled = false
}

/**
* Mark that the canvas is resized. If the size is changed, the renderer and all render targets are resized. This happens before the render of the next frame.
*/
resize = () => {
this._needsResize = true
this.setDirty()
}

private _needsReset = true // renderer reset
/**
* Set the viewer to dirty and trigger render of the next frame.
* @param source - The source of the dirty event. like plugin or 3d object
* @param event - The event that triggered the dirty event.
*/
setDirty(source?: any, event?: Event): void {
this._needsReset = true
source = source ?? this
this.dispatchEvent({...event ?? {}, type: 'update', source})
}

/**
* The renderer for the viewer that's attached to the canvas. This is wrapper around WebGLRenderer and EffectComposer and manages post-processing passes and rendering logic
* @deprecated - use {@link renderManager} instead
*/
get renderer(): ViewerRenderManager {
this.console.error('renderer is deprecated, use renderManager instead')
return this.renderManager
}

/** /**
* Add an object/model/material/viewer-config/plugin-preset/... to the viewer scene from url or an {@link IAsset} object. * Add an object/model/material/viewer-config/plugin-preset/... to the viewer scene from url or an {@link IAsset} object.
* Same as {@link AssetManager.addAssetSingle} * Same as {@link AssetManager.addAssetSingle}
return await this.assetManager.importer.importSingle<T>(obj, options) return await this.assetManager.importer.importSingle<T>(obj, options)
} }


/**
* Exports an object/mesh/material/texture/render-target/plugin-preset/viewer to a blob.
* If no object is given, a glb is exported with the current viewer state.
* @param obj
* @param options
*/
async export(obj?: IObject3D|IMaterial|ITexture|IRenderTarget|IViewerPlugin|(typeof this), options?: ExportFileOptions) {
if (!obj) obj = this._scene // this will export the glb with the scene and viewer config
if ((<typeof this>obj).type === this.type) return jsonToBlob((<typeof this>obj).exportConfig())
if ((<IViewerPlugin>obj).constructor?.PluginType) return jsonToBlob(this.exportPluginConfig(<IViewerPlugin>obj))
return await this.assetManager.exporter.exportObject(<IObject3D|IMaterial|ITexture|IRenderTarget>obj, options)
}

/** /**
* Set the environment map of the scene from url or an {@link IAsset} object. * Set the environment map of the scene from url or an {@link IAsset} object.
* @param map * @param map
return this._scene.background return this._scene.background
} }


/**
* Exports an object/mesh/material/texture/render-target/plugin-preset/viewer to a blob.
* If no object is given, a glb is exported with the current viewer state.
* @param obj
* @param options
*/
async export(obj?: IObject3D|IMaterial|ITexture|IRenderTarget|IViewerPlugin|(typeof this), options?: ExportFileOptions) {
if (!obj) obj = this._scene // this will export the glb with the scene and viewer config
if ((<typeof this>obj).type === this.type) return jsonToBlob((<typeof this>obj).exportConfig())
if ((<IViewerPlugin>obj).constructor?.PluginType) return jsonToBlob(this.exportPluginConfig(<IViewerPlugin>obj))
return await this.assetManager.exporter.exportObject(<IObject3D|IMaterial|ITexture|IRenderTarget>obj, options)
}

/**
* Export the scene to a file (default: glb with viewer config) and return a blob
* @param options
*/
async exportScene(options?: ExportFileOptions): Promise<BlobExt | undefined> {
return this.assetManager.exporter.exportObject(this._scene.modelRoot, options)
}

async getScreenshotBlob({mimeType = 'image/jpeg', quality = 90} = {}): Promise<Blob | null> {
const blobPromise = async()=> new Promise<Blob|null>((resolve) => {
this._canvas.toBlob((blob) => {
resolve(blob)
}, mimeType, quality)
})
if (!this.renderEnabled) return blobPromise()
return await this.doOnce('postFrame', async() => {
this.renderEnabled = false
const blob = await blobPromise()
this.renderEnabled = true
return blob
})
}

async getScreenshotDataUrl({mimeType = 'image/jpeg', quality = 90} = {}): Promise<string | null> {
if (!this.renderEnabled) return this._canvas.toDataURL(mimeType, quality)
return await this.doOnce('postFrame', () => this._canvas.toDataURL(mimeType, quality))
}

/** /**
* Disposes the viewer and frees up all resource and events. Do not use the viewer after calling dispose. * Disposes the viewer and frees up all resource and events. Do not use the viewer after calling dispose.
* @note - If you want to reuse the viewer, set viewer.enabled to false instead, then set it to true again when required. To dispose all the objects, materials in the scene use `viewer.scene.disposeSceneModels()` * @note - If you want to reuse the viewer, set viewer.enabled to false instead, then set it to true again when required. To dispose all the objects, materials in the scene use `viewer.scene.disposeSceneModels()`
this.dispatchEvent({type: 'dispose'}) this.dispatchEvent({type: 'dispose'})
} }


private _animationLoop(event: IAnimationLoopEvent): void {
/**
* Mark that the canvas is resized. If the size is changed, the renderer and all render targets are resized. This happens before the render of the next frame.
*/
resize = () => {
this._needsResize = true
this.setDirty()
}

/**
* Set the viewer to dirty and trigger render of the next frame.
* @param source - The source of the dirty event. like plugin or 3d object
* @param event - The event that triggered the dirty event.
*/
setDirty(source?: any, event?: Event): void {
this._needsReset = true
source = source ?? this
this.dispatchEvent({...event ?? {}, type: 'update', source})
}

protected _animationLoop(event: IAnimationLoopEvent): void {
if (!this.enabled || !this.renderEnabled) return if (!this.enabled || !this.renderEnabled) return
if (this._isRenderingFrame) { if (this._isRenderingFrame) {
this.console.warn('animation loop: frame skip') // not possible actually, since this is not async this.console.warn('animation loop: frame skip') // not possible actually, since this is not async


} }



/**
* Get the HTML Element containing the canvas
* @returns {HTMLElement}
*/
get container(): HTMLElement {
return this._container
}

/**
* Get the HTML Canvas Element where the viewer is rendering
* @returns {HTMLCanvasElement}
*/
get canvas(): HTMLCanvasElement {
return this._canvas
}

/** /**
* Get the Plugin by a constructor type or by the string type. * Get the Plugin by a constructor type or by the string type.
* Use string type if the plugin is not a dependency and you don't want to bundle the plugin. * Use string type if the plugin is not a dependency and you don't want to bundle the plugin.
} }


/** /**
* Get the Plugin by the string type.
* @deprecated - Use {@link getPlugin} instead.
* Get the Plugin by a constructor type or add a new plugin of the specified type if it doesn't exist.
* @param type * @param type
* @returns {T | undefined}
* @param args - arguments for the constructor of the plugin, used when a new plugin is created.
*/ */
getPluginByType<T extends IViewerPlugin>(type: string): T | undefined {
return this.plugins[type] as T | undefined
}

async getOrAddPlugin<T extends IViewerPlugin>(type: Class<T>, ...args: ConstructorParameters<Class<T>>): Promise<T> { async getOrAddPlugin<T extends IViewerPlugin>(type: Class<T>, ...args: ConstructorParameters<Class<T>>): Promise<T> {
const plugin = this.getPlugin(type) const plugin = this.getPlugin(type)
if (plugin) return plugin if (plugin) return plugin
return this.addPlugin(type, ...args) return this.addPlugin(type, ...args)
} }


/**
* Get the Plugin by a constructor type or add a new plugin to the viewer of the specified type if it doesn't exist(sync).
* @param type
* @param args - arguments for the constructor of the plugin, used when a new plugin is created.
*/
getOrAddPluginSync<T extends IViewerPluginSync>(type: Class<T>, ...args: ConstructorParameters<Class<T>>): T { getOrAddPluginSync<T extends IViewerPluginSync>(type: Class<T>, ...args: ConstructorParameters<Class<T>>): T {
const plugin = this.getPlugin(type) const plugin = this.getPlugin(type)
if (plugin) return plugin if (plugin) return plugin
return p return p
} }


/**
* Add multiple plugins to the viewer.
* @param plugins - List of plugin instances or classes
*/
async addPlugins(plugins: (IViewerPlugin | Class<IViewerPlugin>)[]): Promise<void> { async addPlugins(plugins: (IViewerPlugin | Class<IViewerPlugin>)[]): Promise<void> {
for (const p of plugins) await this.addPlugin(p) for (const p of plugins) await this.addPlugin(p)
} }


/**
* Add multiple plugins to the viewer(sync).
* @param plugins - List of plugin instances or classes
*/
async addPluginsSync(plugins: (IViewerPluginSync | Class<IViewerPluginSync>)[]): Promise<void> { async addPluginsSync(plugins: (IViewerPluginSync | Class<IViewerPluginSync>)[]): Promise<void> {
for (const p of plugins) this.addPluginSync(p) for (const p of plugins) this.addPluginSync(p)
} }
this.setDirty(p) this.setDirty(p)
} }


/**
* Remove a plugin instance or a plugin class(sync). Works similar to {@link ThreeViewer.addPluginSync}
* @param p
* @param dispose
*/
removePluginSync(p: IViewerPluginSync, dispose = true): void { removePluginSync(p: IViewerPluginSync, dispose = true): void {
const type = p.constructor.PluginType const type = p.constructor.PluginType
if (!this.plugins[type]) return if (!this.plugins[type]) return
this.resize() this.resize()
} }


// private _addSceneObject = (e: IEvent<any>) => {
// if (!e || !e.object) return
// const config = e.object.__importedViewerConfig // this is set in gltf.ts when gltf file is imported. This is done here so that scene settings are applied whenever the imported object is added to scene.
// if (!config) return
// this.fromJSON(config, config.resources)
// }


/**
* @deprecated use {@link assetManager} instead.
* Gets the Asset manager, contains useful functions for managing, loading and inserting assets.
*/
getManager(): AssetManager|undefined {
return this.assetManager
}

// todo
// public async fitToView(selected?: Object3D, distanceMultiplier = 1.5, duration?: number, ease?: Easing|EasingFunctionType) {
// const camViews = this.getPluginByType<CameraViewPlugin>('CameraViews')
// if (!camViews) {
// this.console.error('CameraViews plugin is required for fitToView to work')
// return
// }
// await camViews?.animateToFitObject(selected, distanceMultiplier, duration, ease, {min: (this.scene.activeCamera.getControls<OrbitControls3>()?.minDistance ?? 0.5) + 0.5, max: 1000.0})
// }

/** /**
* Traverse all objects in scene model root. * Traverse all objects in scene model root.
* @param callback * @param callback
this._scene.modelRoot.traverse(callback) this._scene.modelRoot.traverse(callback)
} }


// todo: create/load texture utils
/**
* Add an object to the scene model root.
* If an imported scene model root is passed, it will be loaded with viewer configuration, unless importConfig is false
* @param imported
* @param options
*/
async addSceneObject<T extends IObject3D|Object3D|RootSceneImportResult = RootSceneImportResult>(imported: T, options?: AddObjectOptions): Promise<T> {
if (imported.userData?.rootSceneModelRoot) {
const obj = <RootSceneImportResult>imported
if (obj.importedViewerConfig && options?.importConfig !== false) await this.importConfig(obj.importedViewerConfig)
this._scene.loadModelRoot(obj, options)
return this._scene.modelRoot as T
}
this._scene.addObject(imported, options)
return imported
}



/** /**
* Serialize all the plugins and their settings to save or create presets. Used in {@link toJSON}. * Serialize all the plugins and their settings to save or create presets. Used in {@link toJSON}.
return data return data
} }



/** /**
* Deserialize all the viewer and plugin settings. * Deserialize all the viewer and plugin settings.
* @note use async {@link ThreeViewer.importConfig} to import a json/config exported with {@link ThreeViewer.exportConfig} or {@link ThreeViewer.toJSON}. * @note use async {@link ThreeViewer.importConfig} to import a json/config exported with {@link ThreeViewer.exportConfig} or {@link ThreeViewer.toJSON}.
return await MetaImporter.ImportMeta(meta, extraResources) return await MetaImporter.ImportMeta(meta, extraResources)
} }


async addSceneObject<T extends IObject3D|Object3D|RootSceneImportResult = RootSceneImportResult>(imported: T, options?: AddObjectOptions): Promise<T> {
if (imported.userData?.rootSceneModelRoot) {
const obj = <RootSceneImportResult>imported
if (obj.importedViewerConfig && options?.importConfig !== false) await this.importConfig(obj.importedViewerConfig)
this._scene.loadModelRoot(obj, options)
return this._scene.modelRoot as T
}
this._scene.addObject(imported, options)
return imported
async doOnce<TRet>(event: IViewerEventTypes, func: (...args: any[]) => TRet): Promise<TRet> {
return new Promise((resolve) => {
const listener = async(...args: any[]) => {
this.removeEventListener(event, listener)
resolve(await func(...args))
}
this.addEventListener(event, listener)
})
} }


private _setActiveCameraView(event: any = {}): void { private _setActiveCameraView(event: any = {}): void {
return p return p
} }


async doOnce<TRet>(event: IViewerEventTypes, func: (...args: any[]) => TRet): Promise<TRet> {
return new Promise((resolve) => {
const listener = async(...args: any[]) => {
this.removeEventListener(event, listener)
resolve(await func(...args))
}
this.addEventListener(event, listener)
})
}

/**
* Export the scene to a file (default: glb with viewer config) and return a blob
* @param options
*/
async exportScene(options?: ExportFileOptions): Promise<BlobExt | undefined> {
return this.assetManager.exporter.exportObject(this._scene.modelRoot, options)
}

async getScreenshotBlob({mimeType = 'image/jpeg', quality = 90} = {}): Promise<Blob | null> {
const blobPromise = async()=> new Promise<Blob|null>((resolve) => {
this._canvas.toBlob((blob) => {
resolve(blob)
}, mimeType, quality)
})
if (!this.renderEnabled) return blobPromise()
return await this.doOnce('postFrame', async() => {
this.renderEnabled = false
const blob = await blobPromise()
this.renderEnabled = true
return blob
})
}

async getScreenshotDataUrl({mimeType = 'image/jpeg', quality = 90} = {}): Promise<string | null> {
if (!this.renderEnabled) return this._canvas.toDataURL(mimeType, quality)
return await this.doOnce('postFrame', () => this._canvas.toDataURL(mimeType, quality))
}


private _renderEnabledChanged(): void { private _renderEnabledChanged(): void {
this.dispatchEvent({type: this.renderEnabled ? 'renderEnabled' : 'renderDisabled'}) this.dispatchEvent({type: this.renderEnabled ? 'renderEnabled' : 'renderDisabled'})
} }
plugins: [], plugins: [],
} }


// todo: find a better fix for context loss and restore?
private _lastSize = new Vector2()
private _onContextRestore = (_: Event) => {
this.enabled = true
this._canvas.width = this._lastSize.width
this._canvas.height = this._lastSize.height
this.resize()
this._scene.setDirty({refreshScene: true, frameFade: false})
}
private _onContextLost = (_: Event) => {
this._lastSize.set(this._canvas.width, this._canvas.height)
this._canvas.width = 2
this._canvas.height = 2
this.resize()
this.enabled = false
}

// private _addSceneObject = (e: IEvent<any>) => {
// if (!e || !e.object) return
// const config = e.object.__importedViewerConfig // this is set in gltf.ts when gltf file is imported. This is done here so that scene settings are applied whenever the imported object is added to scene.
// if (!config) return
// this.fromJSON(config, config.resources)
// }

// todo
// public async fitToView(selected?: Object3D, distanceMultiplier = 1.5, duration?: number, ease?: Easing|EasingFunctionType) {
// const camViews = this.getPluginByType<CameraViewPlugin>('CameraViews')
// if (!camViews) {
// this.console.error('CameraViews plugin is required for fitToView to work')
// return
// }
// await camViews?.animateToFitObject(selected, distanceMultiplier, duration, ease, {min: (this.scene.activeCamera.getControls<OrbitControls3>()?.minDistance ?? 0.5) + 0.5, max: 1000.0})
// }

// todo: create/load texture utils

// region legacy creation functions // region legacy creation functions


// /** // /**


// endregion // endregion


/**
* The renderer for the viewer that's attached to the canvas. This is wrapper around WebGLRenderer and EffectComposer and manages post-processing passes and rendering logic
* @deprecated - use {@link renderManager} instead
*/
get renderer(): ViewerRenderManager {
this.console.error('renderer is deprecated, use renderManager instead')
return this.renderManager
}

/**
* @deprecated use {@link assetManager} instead.
* Gets the Asset manager, contains useful functions for managing, loading and inserting assets.
*/
getManager(): AssetManager|undefined {
return this.assetManager
}

/**
* Get the Plugin by the string type.
* @deprecated - Use {@link getPlugin} instead.
* @param type
* @returns {T | undefined}
*/
getPluginByType<T extends IViewerPlugin>(type: string): T | undefined {
return this.plugins[type] as T | undefined
}

} }

+ 1
- 1
src/viewer/version.ts Wyświetl plik

export const VERSION = '0.0.12'
export const VERSION = '0.0.14'

Ładowanie…
Anuluj
Zapisz