Преглед на файлове

Add plugins to load ktx, ktx2, ply, stl files and their examples. Add html-sample example.

master
Palash Bansal преди 2 години
родител
ревизия
1f61ff4817
No account linked to committer's email address

+ 2
- 2
examples/examples-utils/simple-code-preview.mjs Целия файл

const exampleStyle = document.querySelector('#example-style') const exampleStyle = document.querySelector('#example-style')
const css = exampleStyle ? exampleStyle.textContent : '' const css = exampleStyle ? exampleStyle.textContent : ''
const importMap = document.querySelector('script[type="importmap"]') const importMap = document.querySelector('script[type="importmap"]')
const imports = JSON.parse(importMap.textContent||'{}').imports||{}
const imports = importMap ? JSON.parse(importMap.textContent||'{}').imports||{} : {}
Object.entries(imports).forEach(([k,v])=>imports[k] = v.replace(/^\.\/\.\.\/\.\.\//, rootPath)) // ./../../ -> rootPath Object.entries(imports).forEach(([k,v])=>imports[k] = v.replace(/^\.\/\.\.\/\.\.\//, rootPath)) // ./../../ -> rootPath
function replaceImports(code) { function replaceImports(code) {
for (const [name, link] of Object.entries(imports)) code = code.replaceAll(` from '${name}'`, ` from '${link}'`) for (const [name, link] of Object.entries(imports)) code = code.replaceAll(` from '${name}'`, ` from '${link}'`)
.replaceAll(` from '../`, ` from '${rootPath+examplePath}`) .replaceAll(` from '../`, ` from '${rootPath+examplePath}`)
} }
setupCodePreview( setupCodePreview(
document.getElementById('canvas-container') || document.querySelector('.code-preview-container'),
document.getElementById('canvas-container') || document.querySelector('.code-preview-container') || document.body,
scripts, scripts,
scripts.map(s=>s.textContent ? 'js' : s.split('.').pop()), // title scripts.map(s=>s.textContent ? 'js' : s.split('.').pop()), // title
scripts.map(s=>(typeof s === 'string' && s.endsWith('.js')) ? s : (codePath+examplePath+window.location.pathname.split('/examples/').pop().replace('index.html', '')+(s.textContent ? 'index.html' : s))), // todo: github link scripts.map(s=>(typeof s === 'string' && s.endsWith('.js')) ? s : (codePath+examplePath+window.location.pathname.split('/examples/').pop().replace('index.html', '')+(s.textContent ? 'index.html' : s))), // todo: github link

+ 34
- 0
examples/html-sample/index.html Целия файл

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Threepipe HTML/JS Sample</title>
<style>
html, body{
width: 100%;
height: 100%;
margin: 0;
overflow: hidden;
}
</style>

<script type="module" src="../examples-utils/simple-code-preview.mjs"></script>
</head>
<body>
<canvas id="three-canvas" style="width: 800px; height: 600px;"></canvas>
<script id="example-script" type="module" data-scripts="./index.html">
import {ThreeViewer} from 'https://threepipe.org/dist/index.mjs'
const viewer = new ThreeViewer({canvas: document.getElementById('three-canvas')})

// Load an environment map
const envPromise = viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr')
const modelPromise = viewer.load('https://threejs.org/examples/models/gltf/DamagedHelmet/glTF/DamagedHelmet.gltf', {
autoCenter: true,
autoScale: true,
})

Promise.all([envPromise, modelPromise]).then(([env, model])=>{
console.log('Loaded', model, env, viewer)
})
</script>
</body>

+ 45
- 0
examples/image-load/index.html Целия файл

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Image Load</title>
<!-- 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;
}
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 .png, .jpeg, .jpg, .svg, .ico, .avif, .webp files here</p>
<canvas id="mcanvas"></canvas>
</div>

</body>

+ 62
- 0
examples/image-load/script.ts Целия файл

import {_testFinish, ITexture, Mesh, PlaneGeometry, SRGBColorSpace, ThreeViewer, UnlitMaterial} from 'threepipe'

async function init() {

const viewer = new ThreeViewer({
canvas: document.getElementById('mcanvas') as HTMLCanvasElement,
msaa: true,
dropzone: {
allowedExtensions: ['png', 'jpg', 'jpeg', 'svg', 'webp', 'avif', 'ico'],
addOptions: {
disposeSceneObjects: false,
autoSetEnvironment: false, // when hdr is dropped
autoSetBackground: false,
},
},
})

viewer.scene.setBackgroundColor('#555555')

const urls = [
'https://threejs.org/examples/textures/sprite0.png',
'https://threejs.org/examples/textures/uv_grid_opengl.jpg',
'https://threejs.org/examples/models/svg/style-css-inside-defs.svg',
'https://threejs.org/examples/textures/tiltbrush/Light.webp',
// todo: avif
'https://threejs.org/favicon.ico',
]

const geometry = new PlaneGeometry(1, 1)
let i = 0
for (const url of urls) {
// Load the url as a Texture
const texture = await viewer.load<ITexture>(url)
if (!texture) continue
texture.colorSpace = SRGBColorSpace
const material = new UnlitMaterial({
map: texture,
transparent: true,
})
const plane = new Mesh(geometry, material)
plane.position.set(i % 3 - 1, -Math.floor(i / 3) + 1, 0)
viewer.scene.addObject(plane)
i++
}

// Listen to when a file is dropped
viewer.assetManager.addEventListener('loadAsset', (e)=>{
if (!e.data.isTexture) return
const texture = e.data as ITexture
texture.colorSpace = SRGBColorSpace
const material = new UnlitMaterial({
map: texture,
transparent: true,
})
const plane = new Mesh(geometry, material)
plane.position.set(i % 3 - 1, -Math.floor(i / 3) + 1, 0)
viewer.scene.addObject(plane)
i++
})
}

init().then(_testFinish)

+ 9
- 0
examples/index.html Целия файл

<li><a href="./drc-load/">DRACO(DRC) Load </a></li> <li><a href="./drc-load/">DRACO(DRC) Load </a></li>
<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="./ply-load/">PLY Load </a></li>
<li><a href="./stl-load/">STL Load </a></li>
<li><a href="./ktx2-load/">KTX2 Load </a></li>
<li><a href="./ktx-load/">KTX Load </a></li>
</ul> </ul>
<h2 class="category">Export</h2> <h2 class="category">Export</h2>
<ul> <ul>
<li><a href="./3dm-to-glb/">Convert 3DM to GLB </a></li> <li><a href="./3dm-to-glb/">Convert 3DM to GLB </a></li>
<li><a href="./hdr-to-exr/">Convert HDR to EXR </a></li> <li><a href="./hdr-to-exr/">Convert HDR to EXR </a></li>
</ul> </ul>
<h2 class="category">Samples</h2>
<ul>
<li><a href="./html-sample/">HTML/JS Sample </a></li>
</ul>
<h2 class="category">Tests</h2> <h2 class="category">Tests</h2>
<ul> <ul>
<li><a href="./gltf-transmission-test/">GLTF Transmission Test </a></li> <li><a href="./gltf-transmission-test/">GLTF Transmission Test </a></li>

+ 45
- 0
examples/ktx-load/index.html Целия файл

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>KTX Texture Load</title>
<!-- 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;
}
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 .ktx files here</p>
<canvas id="mcanvas"></canvas>
</div>

</body>

+ 85
- 0
examples/ktx-load/script.ts Целия файл

import {
_testFinish,
ITexture,
KTXLoadPlugin,
Mesh,
PlaneGeometry,
SRGBColorSpace,
ThreeViewer,
UnlitMaterial,
} from 'threepipe'

async function init() {

const viewer = new ThreeViewer({
canvas: document.getElementById('mcanvas') as HTMLCanvasElement,
msaa: true,
dropzone: {
allowedExtensions: ['ktx'],
},
})
viewer.addPluginSync(KTXLoadPlugin)

viewer.scene.setBackgroundColor('#555555')

const urls = []

// Checking which ktx formats are supported by the browser
const formats = {
astc: viewer.renderManager.renderer.extensions.has('WEBGL_compressed_texture_astc'),
etc1: viewer.renderManager.renderer.extensions.has('WEBGL_compressed_texture_etc1'),
s3tc: viewer.renderManager.renderer.extensions.has('WEBGL_compressed_texture_s3tc'),
pvrtc: viewer.renderManager.renderer.extensions.has('WEBGL_compressed_texture_pvrtc'),
}

if (formats.pvrtc) urls.push(
'https://threejs.org/examples/textures/compressed/disturb_PVR2bpp.ktx',
'https://threejs.org/examples/textures/compressed/lensflare_PVR4bpp.ktx'
)
if (formats.s3tc) urls.push(
'https://threejs.org/examples/textures/compressed/disturb_BC1.ktx',
'https://threejs.org/examples/textures/compressed/lensflare_BC3.ktx'
)
if (formats.etc1) urls.push(
'https://threejs.org/examples/textures/compressed/disturb_ETC1.ktx'
)

if (formats.astc) urls.push(
'https://threejs.org/examples/textures/compressed/disturb_ASTC4x4.ktx',
'https://threejs.org/examples/textures/compressed/lensflare_ASTC8x8.ktx'
)

const geometry = new PlaneGeometry(1, 1)
let i = 0
for (const url of urls) {
// Load the url as a Texture
const texture = await viewer.load<ITexture>(url)
if (!texture) continue
texture.colorSpace = SRGBColorSpace
const material = new UnlitMaterial({
map: texture,
transparent: true,
})
const plane = new Mesh(geometry, material)
plane.position.set(i % 3 - 1, -Math.floor(i / 3) + 1, 0)
viewer.scene.addObject(plane)
i++
}

// Listen to when a file is dropped
viewer.assetManager.addEventListener('loadAsset', (e)=>{
if (!e.data.isTexture) return
const texture = e.data as ITexture
texture.colorSpace = SRGBColorSpace
const material = new UnlitMaterial({
map: texture,
transparent: true,
})
const plane = new Mesh(geometry, material)
plane.position.set(i % 3 - 1, -Math.floor(i / 3) + 1, 0)
viewer.scene.addObject(plane)
i++
})
}

init().then(_testFinish)

+ 45
- 0
examples/ktx2-load/index.html Целия файл

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>KTX2 Texture Load</title>
<!-- 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;
}
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 .ktx2 files here</p>
<canvas id="mcanvas"></canvas>
</div>

</body>

+ 77
- 0
examples/ktx2-load/script.ts Целия файл

import {
_testFinish,
ITexture,
KTX2LoadPlugin,
Mesh,
PlaneGeometry,
SRGBColorSpace,
ThreeViewer,
UnlitMaterial,
} from 'threepipe'
import {BufferGeometry} from 'three'

async function init() {

const viewer = new ThreeViewer({
canvas: document.getElementById('mcanvas') as HTMLCanvasElement,
msaa: true,
dropzone: {
allowedExtensions: ['ktx2'],
},
})
viewer.addPluginSync(KTX2LoadPlugin)

viewer.scene.setBackgroundColor('#555555')

const urls = [
'https://threejs.org/examples/textures/compressed/sample_etc1s.ktx2',
'https://threejs.org/examples/textures/compressed/sample_uastc.ktx2',
'https://threejs.org/examples/textures/compressed/sample_uastc_zstd.ktx2',
]

// PlaneGeometry UVs assume flipY=true, which compressed textures don't support.
const geometry = flipY(new PlaneGeometry(1, 1))
let i = 0
for (const url of urls) {
// Load the url as a Texture
const texture = await viewer.load<ITexture>(url)
if (!texture) continue
texture.colorSpace = SRGBColorSpace
const material = new UnlitMaterial({
map: texture,
transparent: true,
})
const plane = new Mesh(geometry, material)
plane.position.set(i % 3 - 1, -Math.floor(i / 3) + 1, 0)
viewer.scene.addObject(plane)
i++
}

// Listen to when a file is dropped
viewer.assetManager.addEventListener('loadAsset', (e)=>{
if (!e.data.isTexture) return
const texture = e.data as ITexture
texture.colorSpace = SRGBColorSpace
const material = new UnlitMaterial({
map: texture,
transparent: true,
})
const plane = new Mesh(geometry, material)
plane.position.set(i % 3 - 1, -Math.floor(i / 3) + 1, 0)
viewer.scene.addObject(plane)
i++
})


}

init().then(_testFinish)

/** Correct UVs to be compatible with `flipY=false` textures. */
function flipY(geometry: BufferGeometry) {
const uv = geometry.attributes.uv
for (let i = 0; i < uv.count; i++) {
uv.setY(i, 1 - uv.getY(i))
}
return geometry
}

+ 34
- 0
examples/ply-load/index.html Целия файл

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>PLY Load</title>
<!-- 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>

+ 32
- 0
examples/ply-load/script.ts Целия файл

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

async function init() {

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

viewer.addPluginSync(PLYLoadPlugin)

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/ply/ascii/dolphins_colored.ply', options),
viewer.load<IObject3D>('https://threejs.org/examples/models/ply/binary/Lucy100k.ply', options),
])

}

init().then(_testFinish)

+ 34
- 0
examples/stl-load/index.html Целия файл

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>STL Load</title>
<!-- 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>

+ 33
- 0
examples/stl-load/script.ts Целия файл

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

async function init() {

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

viewer.addPluginSync(STLLoadPlugin)

const options = {
autoCenter: true,
autoScale: true,
}
const res = await Promise.all([
viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr'),
viewer.load<IObject3D>('https://threejs.org/examples/models/stl/ascii/slotted_disk.stl', options),
viewer.load<IObject3D>('https://threejs.org/examples/models/stl/binary/pr2_head_pan.stl', options),
])
console.log(res)

}

init().then(_testFinish)

+ 17
- 8
examples/tweakpane-editor/script.ts Целия файл

DropzonePlugin, DropzonePlugin,
FullScreenPlugin, FullScreenPlugin,
HalfFloatType, HalfFloatType,
IObject3D,
KTX2LoadPlugin,
KTXLoadPlugin,
NormalBufferPlugin, NormalBufferPlugin,
PLYLoadPlugin,
RenderTargetPreviewPlugin, RenderTargetPreviewPlugin,
Rhino3dmLoadPlugin,
SceneUiConfigPlugin, SceneUiConfigPlugin,
STLLoadPlugin,
ThreeViewer, ThreeViewer,
TonemapPlugin, TonemapPlugin,
ViewerUiConfigPlugin, ViewerUiConfigPlugin,
canvas: document.getElementById('mcanvas') as HTMLCanvasElement, canvas: document.getElementById('mcanvas') as HTMLCanvasElement,
msaa: true, msaa: true,
rgbm: true, rgbm: true,
zPrepass: false, // set it to true if you only have opaque objects in the scene to get better performance.
dropzone: { dropzone: {
addOptions: { addOptions: {
clearSceneObjects: false, // clear the scene before adding new objects on drop. clearSceneObjects: false, // clear the scene before adding new objects on drop.
new DepthBufferPlugin(HalfFloatType, true, true), new DepthBufferPlugin(HalfFloatType, true, true),
new NormalBufferPlugin(HalfFloatType, false), new NormalBufferPlugin(HalfFloatType, false),
new RenderTargetPreviewPlugin(false), new RenderTargetPreviewPlugin(false),
new KTX2LoadPlugin(),
new KTXLoadPlugin(),
new PLYLoadPlugin(),
new Rhino3dmLoadPlugin(),
new STLLoadPlugin(),
]) ])


const rt = viewer.getOrAddPluginSync(RenderTargetPreviewPlugin) const rt = viewer.getOrAddPluginSync(RenderTargetPreviewPlugin)
['Debug']: [RenderTargetPreviewPlugin], ['Debug']: [RenderTargetPreviewPlugin],
}) })


await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr', {
setBackground: true,
})
await viewer.load<IObject3D>('https://threejs.org/examples/models/gltf/DamagedHelmet/glTF/DamagedHelmet.gltf', {
autoCenter: true,
autoScale: true,
})
await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr')

// await viewer.load<IObject3D>('https://threejs.org/examples/models/gltf/DamagedHelmet/glTF/DamagedHelmet.gltf', {
// autoCenter: true,
// autoScale: true,
// })


// const model = result?.getObjectByName('node_damagedHelmet_-6514') // const model = result?.getObjectByName('node_damagedHelmet_-6514')
// const config = model?.uiConfig // const config = model?.uiConfig

+ 1
- 1
src/assetmanager/IImporter.ts Целия файл

export interface ILoader<T = any, T2 = any> extends Loader, Partial<IDisposable> { export interface ILoader<T = any, T2 = any> extends Loader, Partial<IDisposable> {
loadAsync(url: string, onProgress?: (event: ProgressEvent) => void): Promise<any>; loadAsync(url: string, onProgress?: (event: ProgressEvent) => void): Promise<any>;
/** /**
* Transform after load, like convert geometry to mesh, etc. for reference see {@link DRACOLoader2}
* Transform after load, like convert geometry to mesh, etc. for reference see {@link DRACOLoader2} or {@link PLYLoadPlugin}
* @param res - result of load * @param res - result of load
* @param options * @param options
*/ */

+ 85
- 0
src/plugins/import/KTX2LoadPlugin.ts Целия файл

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

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

public static readonly PluginType = 'KTX2LoadPlugin'
private _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/'

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

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

dispose() {
return
}

}

export class KTX2Loader2 extends KTX2Loader implements ILoader {
async createTexture(buffer: ArrayBuffer, config: any): Promise<CompressedTexture> {
const buffer2 = new Uint8Array(buffer.slice(0)) // clones the buffer
const texture = (await super.createTexture(buffer, config)) as CompressedTexture & ITexture
texture.source._sourceImgBuffer = buffer2 // keep the same buffer when cloned and all, used in serializeTextureInExtras
texture.userData.mimeType = 'image/ktx2'
texture.toJSON = (meta?: any)=>{
return serializeTextureInExtras(texture, meta, texture.name, 'image/ktx2')
}
texture.clone = ()=>{
throw new Error('ktx2 texture cloning not supported')
}
return texture
}

}

export const KHR_TEXTURE_BASISU = 'KHR_texture_basisu'

const glTFTextureBasisUExtensionExport = (w: GLTFWriter2)=> ({
writeTexture: (texture: ITexture&ImportResultExtras, textureDef: any) => {
// if (!w.options.embedImages) return // option is removed.
if (texture.userData.mimeType !== 'image/ktx2') return
if (textureDef.source !== undefined && textureDef.source !== null) {
console.warn('ktx2 export: source already set')
return
}
const sourceBuffer = texture.source._sourceImgBuffer || texture.__sourceBuffer // todo do this for all images that have a __sourceBuffer (in GLTFExporter.processImage or GLTFWriter2.processTexture)
if (!sourceBuffer) {
console.warn('ktx2 export: no source buffer for ktx2')
return
}

textureDef.extensions = textureDef.extensions || {}

const extensionDef: any = {}

const blob = new Blob([sourceBuffer], {type: 'image/ktx2'})
extensionDef.source = w.processImageBlob(blob, texture)

textureDef.extensions[ KHR_TEXTURE_BASISU ] = extensionDef
w.extensionsUsed[ KHR_TEXTURE_BASISU ] = true
},
})


+ 27
- 0
src/plugins/import/KTXLoadPlugin.ts Целия файл

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

/**
* Adds support for loading `.ktx`, `image/ktx` files and data uris.
* @category Plugins
*/
export class KTXLoadPlugin implements IViewerPluginSync {
declare ['constructor']: typeof 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
}

}

+ 36
- 0
src/plugins/import/PLYLoadPlugin.ts Целия файл

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

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

public static readonly PluginType = 'PLYLoadPlugin'
private _importer = new Importer(class extends PLYLoader 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)})) : undefined
}
}, ['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
}

}

+ 36
- 0
src/plugins/import/STLLoadPlugin.ts Целия файл

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

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

public static readonly PluginType = 'STLLoadPlugin'
private _importer = new Importer(class extends STLLoader 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)})) : undefined
}
}, ['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
}

}

+ 4
- 0
src/plugins/index.ts Целия файл



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


// postprocessing // postprocessing
export {TonemapPlugin} from './postprocessing/TonemapPlugin' export {TonemapPlugin} from './postprocessing/TonemapPlugin'

+ 1
- 1
src/utils/index.ts Целия файл

export {GLStatsJS} from './GLStatsJS' export {GLStatsJS} from './GLStatsJS'
export {CustomContextMenu} from './CustomContextMenu' export {CustomContextMenu} from './CustomContextMenu'
export {Dropzone, type DropFile, type ListenerCallback, type DropEventType} from './Dropzone' export {Dropzone, type DropFile, type ListenerCallback, type DropEventType} from './Dropzone'
export {ThreeSerialization, type SerializationMetaType, type SerializationResourcesType, MetaImporter, metaToResources, getEmptyMeta, metaFromResources, convertArrayBufferToStringsInMeta, convertStringsToArrayBuffersInMeta, copyMaterialUserData, copyObject3DUserData, copyUserData, copyTextureUserData, jsonToBlob} from './serialization'
export {ThreeSerialization, type SerializationMetaType, type SerializationResourcesType, MetaImporter, metaToResources, getEmptyMeta, metaFromResources, convertArrayBufferToStringsInMeta, convertStringsToArrayBuffersInMeta, copyMaterialUserData, copyObject3DUserData, copyUserData, copyTextureUserData, jsonToBlob, serializeTextureInExtras} from './serialization'
export {shaderReplaceString} from './shader-helpers' export {shaderReplaceString} from './shader-helpers'
export {makeGLBFile} from './gltf' export {makeGLBFile} from './gltf'



+ 45
- 1
src/utils/serialization.ts Целия файл

Vector4, Vector4,
} from 'three' } from 'three'
import type {AssetImporter, AssetManager, MaterialManager} from '../assetmanager' import type {AssetImporter, AssetManager, MaterialManager} from '../assetmanager'
import {BlobExt, IAssetImporter} from '../assetmanager'
import {BlobExt, IAssetImporter, ImportResultExtras} from '../assetmanager'
import {ThreeViewer} from '../viewer' import {ThreeViewer} from '../viewer'
import {ITexture} from '../core' import {ITexture} from '../core'
import {IRenderTarget, RenderManager} from '../rendering' import {IRenderTarget, RenderManager} from '../rendering'
b.ext = 'json' b.ext = 'json'
return b return b
} }



/**
* Used in {@link LUTCubeTextureWrapper} and {@link KTX2LoadPlugin} and imported in {@link loadConfigResources}
* @param texture
* @param meta
* @param name
* @param mime
*/
export function serializeTextureInExtras(texture: ITexture & ImportResultExtras, meta: any, name?: string, mime?: string) {
if (meta?.extras[texture.uuid]) return {uuid: texture.uuid, resource: 'extras'}

let url: any = ''
if (texture.source?._sourceImgBuffer || texture.__sourceBuffer) {
// serialize blob to data in image.
// Note: do not change to Uint16Array because it's encoded to rgbe in `processViewer`
const data = new Uint8Array(texture.source?._sourceImgBuffer || texture.__sourceBuffer as ArrayBuffer)
const mimeType = mime || texture.userData.mimeType || ''
url = {
data: Array.from(data), // texture need to be a normal array, not a typed array.
type: data.constructor.name,
path: texture.userData.__sourceBlob?.name || texture.userData.rootPath || 'file.' + mimeType.split('/')[1],
}
if (mimeType) url.mimeType = mimeType
} else if (texture.userData.rootPath) {
url = texture.userData.rootPath
} else {
console.error('Unable to serialize LUT texture, not loaded through asset manager.')
}

const tex = {
uuid: texture.uuid,
url,
userData: copyTextureUserData({}, texture.userData),
type: texture.type,
name: name || texture.name,
}
if (meta?.extras) {
meta.extras[texture.uuid] = tex
return {uuid: texture.uuid, resource: 'extras'}
}
return tex
}

Loading…
Отказ
Запис