Sfoglia il codice sorgente

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

master
Palash Bansal 2 anni fa
parent
commit
1f61ff4817
Nessun account collegato all'indirizzo email del committer

+ 2
- 2
examples/examples-utils/simple-code-preview.mjs Vedi File

@@ -10,7 +10,7 @@ if(exampleScript.textContent) scripts.push(exampleScript)
const exampleStyle = document.querySelector('#example-style')
const css = exampleStyle ? exampleStyle.textContent : ''
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
function replaceImports(code) {
for (const [name, link] of Object.entries(imports)) code = code.replaceAll(` from '${name}'`, ` from '${link}'`)
@@ -19,7 +19,7 @@ function replaceImports(code) {
.replaceAll(` from '../`, ` from '${rootPath+examplePath}`)
}
setupCodePreview(
document.getElementById('canvas-container') || document.querySelector('.code-preview-container'),
document.getElementById('canvas-container') || document.querySelector('.code-preview-container') || document.body,
scripts,
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

+ 34
- 0
examples/html-sample/index.html Vedi File

@@ -0,0 +1,34 @@
<!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 Vedi File

@@ -0,0 +1,45 @@
<!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 Vedi File

@@ -0,0 +1,62 @@
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 Vedi File

@@ -241,6 +241,11 @@
<li><a href="./drc-load/">DRACO(DRC) Load </a></li>
<li><a href="./hdr-load/">HDR 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>
<h2 class="category">Export</h2>
<ul>
@@ -265,6 +270,10 @@
<li><a href="./3dm-to-glb/">Convert 3DM to GLB </a></li>
<li><a href="./hdr-to-exr/">Convert HDR to EXR </a></li>
</ul>
<h2 class="category">Samples</h2>
<ul>
<li><a href="./html-sample/">HTML/JS Sample </a></li>
</ul>
<h2 class="category">Tests</h2>
<ul>
<li><a href="./gltf-transmission-test/">GLTF Transmission Test </a></li>

+ 45
- 0
examples/ktx-load/index.html Vedi File

@@ -0,0 +1,45 @@
<!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 Vedi File

@@ -0,0 +1,85 @@
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 Vedi File

@@ -0,0 +1,45 @@
<!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 Vedi File

@@ -0,0 +1,77 @@
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 Vedi File

@@ -0,0 +1,34 @@
<!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 Vedi File

@@ -0,0 +1,32 @@
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 Vedi File

@@ -0,0 +1,34 @@
<!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 Vedi File

@@ -0,0 +1,33 @@
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 Vedi File

@@ -4,10 +4,14 @@ import {
DropzonePlugin,
FullScreenPlugin,
HalfFloatType,
IObject3D,
KTX2LoadPlugin,
KTXLoadPlugin,
NormalBufferPlugin,
PLYLoadPlugin,
RenderTargetPreviewPlugin,
Rhino3dmLoadPlugin,
SceneUiConfigPlugin,
STLLoadPlugin,
ThreeViewer,
TonemapPlugin,
ViewerUiConfigPlugin,
@@ -21,6 +25,7 @@ async function init() {
canvas: document.getElementById('mcanvas') as HTMLCanvasElement,
msaa: true,
rgbm: true,
zPrepass: false, // set it to true if you only have opaque objects in the scene to get better performance.
dropzone: {
addOptions: {
clearSceneObjects: false, // clear the scene before adding new objects on drop.
@@ -37,6 +42,11 @@ async function init() {
new DepthBufferPlugin(HalfFloatType, true, true),
new NormalBufferPlugin(HalfFloatType, false),
new RenderTargetPreviewPlugin(false),
new KTX2LoadPlugin(),
new KTXLoadPlugin(),
new PLYLoadPlugin(),
new Rhino3dmLoadPlugin(),
new STLLoadPlugin(),
])

const rt = viewer.getOrAddPluginSync(RenderTargetPreviewPlugin)
@@ -50,13 +60,12 @@ async function init() {
['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 config = model?.uiConfig

+ 1
- 1
src/assetmanager/IImporter.ts Vedi File

@@ -5,7 +5,7 @@ import {AnyOptions, IDisposable} from 'ts-browser-helpers'
export interface ILoader<T = any, T2 = any> extends Loader, Partial<IDisposable> {
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 options
*/

+ 85
- 0
src/plugins/import/KTX2LoadPlugin.ts Vedi File

@@ -0,0 +1,85 @@
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 Vedi File

@@ -0,0 +1,27 @@
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 Vedi File

@@ -0,0 +1,36 @@
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 Vedi File

@@ -0,0 +1,36 @@
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 Vedi File

@@ -18,6 +18,10 @@ export {FullScreenPlugin} from './interaction/FullScreenPlugin'

// import
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
export {TonemapPlugin} from './postprocessing/TonemapPlugin'

+ 1
- 1
src/utils/index.ts Vedi File

@@ -3,7 +3,7 @@ export {windowDialogWrapper, type IDialogWrapper} from './DialogWrapper'
export {GLStatsJS} from './GLStatsJS'
export {CustomContextMenu} from './CustomContextMenu'
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 {makeGLBFile} from './gltf'


+ 45
- 1
src/utils/serialization.ts Vedi File

@@ -14,7 +14,7 @@ import {
Vector4,
} from 'three'
import type {AssetImporter, AssetManager, MaterialManager} from '../assetmanager'
import {BlobExt, IAssetImporter} from '../assetmanager'
import {BlobExt, IAssetImporter, ImportResultExtras} from '../assetmanager'
import {ThreeViewer} from '../viewer'
import {ITexture} from '../core'
import {IRenderTarget, RenderManager} from '../rendering'
@@ -777,3 +777,47 @@ export function jsonToBlob(json: any): BlobExt {
b.ext = 'json'
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…
Annulla
Salva