mirror of
https://github.com/BinomialLLC/basis_universal.git
synced 2026-09-22 18:34:33 +00:00
Reorganize JS to separate threejs scene setup from Basis texture loading.
This commit is contained in:
169
webgl/gltf-demo/BasisTextureLoader.js
Normal file
169
webgl/gltf-demo/BasisTextureLoader.js
Normal file
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* @author Don McCurdy / https://www.donmccurdy.com
|
||||
* @author Austin Eng / ?
|
||||
* @author Shrek Shao / https://github.com/shrekshao
|
||||
*/
|
||||
|
||||
/**
|
||||
* An example three.js loader for Basis compressed textures.
|
||||
*/
|
||||
THREE.BasisTextureLoader = class BasisTextureLoader {
|
||||
|
||||
constructor () {
|
||||
|
||||
this.etcSupported = false;
|
||||
this.dxtSupported = false;
|
||||
this.pvrtcSupported = false;
|
||||
|
||||
this.format = null;
|
||||
|
||||
}
|
||||
|
||||
detectSupport ( renderer ) {
|
||||
|
||||
const context = renderer.context;
|
||||
|
||||
this.etcSupported = context.getExtension('WEBGL_compressed_texture_etc1');
|
||||
this.dxtSupported = context.getExtension('WEBGL_compressed_texture_s3tc');
|
||||
this.pvrtcSupported = context.getExtension('WEBGL_compressed_texture_pvrtc')
|
||||
|| context.getExtension('WEBKIT_WEBGL_compressed_texture_pvrtc');
|
||||
|
||||
if ( ! this.etcSupported && ! this.dxtSupported && ! this.pvrtcSupported ) {
|
||||
|
||||
throw new Error( 'THREE.BasisTextureLoader: No suitable compressed texture format found.' );
|
||||
|
||||
}
|
||||
|
||||
this.format = this.etcSupported
|
||||
? BASIS_FORMAT.cTFETC1
|
||||
: ( this.dxtSupported
|
||||
? BASIS_FORMAT.cTFBC1
|
||||
: BASIS_FORMAT.cTFPVRTC1_4_OPAQUE_ONLY );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
load ( url, onLoad, onProgress, onError ) {
|
||||
|
||||
fetch( url )
|
||||
.then( ( res ) => res.arrayBuffer() )
|
||||
.then( (arrayBuffer) => this._createTexture( arrayBuffer ) )
|
||||
.then( onLoad )
|
||||
.catch( onError );
|
||||
|
||||
}
|
||||
|
||||
_createTexture ( arrayBuffer ) {
|
||||
|
||||
const BASIS_FORMAT = THREE.BasisTextureLoader.BASIS_FORMAT;
|
||||
const DXT_FORMAT_MAP = THREE.BasisTextureLoader.DXT_FORMAT_MAP;
|
||||
|
||||
const basisFile = new BasisFile( new Uint8Array( arrayBuffer ) );
|
||||
|
||||
const width = basisFile.getImageWidth( 0, 0 );
|
||||
const height = basisFile.getImageHeight( 0, 0 );
|
||||
const images = basisFile.getNumImages();
|
||||
const levels = basisFile.getNumLevels( 0 );
|
||||
|
||||
function cleanup () {
|
||||
|
||||
basisFile.close();
|
||||
basisFile.delete();
|
||||
|
||||
}
|
||||
|
||||
if ( ! width || ! height || ! images || ! levels ) {
|
||||
|
||||
cleanup();
|
||||
throw new Error( 'THREE.BasisTextureLoader: Invalid .basis file' );
|
||||
|
||||
}
|
||||
|
||||
if ( ! basisFile.startTranscoding() ) {
|
||||
|
||||
cleanup();
|
||||
throw new Error( 'THREE.BasisTextureLoader: .startTranscoding failed' );
|
||||
|
||||
}
|
||||
|
||||
const dst = new Uint8Array( basisFile.getImageTranscodedSizeInBytes( 0, 0, this.format ) );
|
||||
|
||||
const startTime = performance.now();
|
||||
|
||||
const status = basisFile.transcodeImage(
|
||||
dst,
|
||||
0,
|
||||
0,
|
||||
this.format,
|
||||
this.etcSupported ? 0 : ( this.dxtSupported ? 1 : 0 ),
|
||||
0
|
||||
);
|
||||
|
||||
console.log( `THREE.BasisTextureLoader: Transcode time: ${performance.now() - startTime}ms`, dst );
|
||||
|
||||
cleanup();
|
||||
|
||||
if ( ! status ) {
|
||||
|
||||
throw new Error( 'THREE.BasisTextureLoader: .transcodeImage failed.' );
|
||||
|
||||
}
|
||||
|
||||
const mipmaps = [ { data: dst, width, height } ];
|
||||
|
||||
let texture;
|
||||
|
||||
if ( this.etcSupported ) {
|
||||
|
||||
texture = new THREE.CompressedTexture( mipmaps, width, height, THREE.RGB_ETC1_Format );
|
||||
|
||||
} else if ( this.dxtSupported ) {
|
||||
|
||||
texture = new THREE.CompressedTexture( mipmaps, width, height, DXT_FORMAT_MAP[ this.format ], THREE.UnsignedByteType );
|
||||
|
||||
} else if ( this.pvrtcSupported ) {
|
||||
|
||||
texture = new THREE.CompressedTexture( mipmaps, width, height, THREE.RGB_PVRTC_4BPPV1_Format );
|
||||
|
||||
} else {
|
||||
|
||||
throw new Error( 'THREE.BasisTextureLoader: No supported format available.' );
|
||||
|
||||
}
|
||||
|
||||
texture.minFilter = THREE.LinearMipMapLinearFilter;
|
||||
texture.magFilter = THREE.LinearFilter;
|
||||
texture.encoding = THREE.sRGBEncoding;
|
||||
texture.generateMipmaps = false;
|
||||
texture.flipY = false;
|
||||
texture.needsUpdate = true;
|
||||
|
||||
return texture;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const BASIS_FORMAT = {
|
||||
cTFETC1: 0,
|
||||
cTFBC1: 1,
|
||||
cTFBC4: 2,
|
||||
cTFPVRTC1_4_OPAQUE_ONLY: 3,
|
||||
cTFBC7_M6_OPAQUE_ONLY: 4,
|
||||
cTFETC2: 5,
|
||||
cTFBC3: 6,
|
||||
cTFBC5: 7,
|
||||
};
|
||||
|
||||
// DXT formats, from:
|
||||
// http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
|
||||
const DXT_FORMAT_MAP = {};
|
||||
const COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0;
|
||||
const COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1;
|
||||
const COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2;
|
||||
const COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3;
|
||||
DXT_FORMAT_MAP[ BASIS_FORMAT.cTFBC1 ] = COMPRESSED_RGB_S3TC_DXT1_EXT;
|
||||
DXT_FORMAT_MAP[ BASIS_FORMAT.cTFBC3 ] = COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||
|
||||
THREE.BasisTextureLoader.BASIS_FORMAT = BASIS_FORMAT;
|
||||
THREE.BasisTextureLoader.DXT_FORMAT_MAP = DXT_FORMAT_MAP;
|
||||
@@ -1,3 +1,8 @@
|
||||
/**
|
||||
* Copyright 2019 the three.js authors
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Rich Tibbett / https://github.com/richtr
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
@@ -6,6 +11,12 @@
|
||||
* @author Don McCurdy / https://www.donmccurdy.com
|
||||
*/
|
||||
|
||||
/**
|
||||
* A modified version of THREE.GLTFLoader, with support for the (hypothetical)
|
||||
* GOOGLE_texture_basis extension. This extension is defined for the sake of
|
||||
* example only – the glTF format will officially reference Basis files within
|
||||
* a KTX2 wrapper.
|
||||
*/
|
||||
THREE.GLTFLoader = ( function () {
|
||||
|
||||
function GLTFLoader( manager ) {
|
||||
|
||||
@@ -3,220 +3,118 @@
|
||||
<head>
|
||||
<script src="https://cdn.jsdelivr.net/npm/three@v0.104.0"></script>
|
||||
<script src="GLTFLoader.js"></script>
|
||||
<script src="BasisTextureLoader.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/three@v0.104.0/examples/js/controls/OrbitControls.js"></script>
|
||||
<style>
|
||||
html, body { width:100%; height:100%; margin:0; padding:0; }
|
||||
canvas { display:block; }
|
||||
#pannel { position: absolute; top: 10px; left: 10px; color: white; background-color:rgba(0.3, 0.3, 0.3, 0.3); padding: 0.5em; max-width: 25%;}
|
||||
#panel { position: absolute; top: 10px; left: 10px; color: white; background-color:rgba(0.3, 0.3, 0.3, 0.3); padding: 0.5em; max-width: 400px;}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script src="./wasm/build/basis_transcoder.js"></script>
|
||||
<script>
|
||||
function log(s) {
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = s;
|
||||
document.getElementById('log').appendChild(div);
|
||||
}
|
||||
|
||||
function logTime(desc, t) {
|
||||
log(desc + t.toFixed(1) + ' ms');
|
||||
}
|
||||
|
||||
/**
|
||||
* Demo created by donmccurdy@, austin@, shrekshao@, with thanks to the Cesium team for
|
||||
* providing the sample model.
|
||||
*/
|
||||
Module.onRuntimeInitialized = () => {
|
||||
|
||||
const { BasisFile, initializeBasis } = Module;
|
||||
|
||||
// DXT formats, from:
|
||||
// http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
|
||||
COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0;
|
||||
COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1;
|
||||
COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2;
|
||||
COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3;
|
||||
|
||||
const BASIS_FORMAT = {
|
||||
cTFETC1: 0,
|
||||
cTFBC1: 1,
|
||||
cTFBC4: 2,
|
||||
cTFPVRTC1_4_OPAQUE_ONLY: 3,
|
||||
cTFBC7_M6_OPAQUE_ONLY: 4,
|
||||
cTFETC2: 5,
|
||||
cTFBC3: 6,
|
||||
cTFBC5: 7,
|
||||
};
|
||||
|
||||
BASIS_FORMAT_NAMES = {};
|
||||
for (var name in BASIS_FORMAT) {
|
||||
BASIS_FORMAT_NAMES[BASIS_FORMAT[name]] = name;
|
||||
}
|
||||
|
||||
DXT_FORMAT_MAP = {};
|
||||
DXT_FORMAT_MAP[BASIS_FORMAT.cTFBC1] = COMPRESSED_RGB_S3TC_DXT1_EXT;
|
||||
DXT_FORMAT_MAP[BASIS_FORMAT.cTFBC3] = COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||
window.BasisFile = BasisFile;
|
||||
|
||||
initializeBasis();
|
||||
|
||||
// Initialize three.js scene and renderer.
|
||||
|
||||
/**
|
||||
* ThreeJS glTF demo created by donmccurdy@, austin@, shrekshao@ below.
|
||||
*/
|
||||
const renderer = new THREE.WebGLRenderer( { antialias: true } );
|
||||
renderer.setSize( window.innerWidth, window.innerHeight );
|
||||
renderer.gammaOutput = true;
|
||||
renderer.gammaFactor = 2.2;
|
||||
|
||||
(function () {
|
||||
const scene = new THREE.Scene();
|
||||
scene.background = new THREE.Color( 0xf0f0f0 );
|
||||
|
||||
const renderer = new THREE.WebGLRenderer({ antialias: true });
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
renderer.gammaOutput = true;
|
||||
renderer.gammaFactor = 2.2;
|
||||
const light = new THREE.AmbientLight();
|
||||
scene.add( light );
|
||||
|
||||
const scene = new THREE.Scene();
|
||||
scene.background = new THREE.Color(0xf0f0f0);
|
||||
const light2 = new THREE.PointLight();
|
||||
scene.add( light2 );
|
||||
|
||||
const light = new THREE.AmbientLight();
|
||||
scene.add(light);
|
||||
const camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.1, 100 );
|
||||
camera.position.set( 8, 6, 5 );
|
||||
camera.lookAt( new THREE.Vector3( 0, -2, 0 ) );
|
||||
|
||||
const light2 = new THREE.PointLight();
|
||||
scene.add(light2);
|
||||
const controls = new THREE.OrbitControls( camera, renderer.domElement );
|
||||
controls.autoRotate = true;
|
||||
|
||||
const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 100);
|
||||
camera.position.set(12, 8, 10);
|
||||
camera.lookAt(new THREE.Vector3(0, -2, 0));
|
||||
// Create BasisTextureLoader and detect supported target formats.
|
||||
|
||||
const controls = new THREE.OrbitControls( camera, renderer.domElement );
|
||||
controls.autoRotate = true;
|
||||
const basisLoader = new THREE.BasisTextureLoader();
|
||||
basisLoader.detectSupport( renderer );
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
camera.aspect = window.innerWidth / window.innerHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
}, false);
|
||||
const formatName = basisLoader.etcSupported
|
||||
? 'ETC1'
|
||||
: ( basisLoader.dxtSupported ? 'BC1' : 'PVRTC' );
|
||||
log(`Transcode to: <strong>${formatName}</strong>`);
|
||||
|
||||
const etcSupported = renderer.context.getExtension('WEBGL_compressed_texture_etc1');
|
||||
const dxtSupported = renderer.context.getExtension('WEBGL_compressed_texture_s3tc');
|
||||
const pvrtcSupported = renderer.context.getExtension('WEBGL_compressed_texture_pvrtc') ||
|
||||
renderer.context.getExtension('WEBKIT_WEBGL_compressed_texture_pvrtc');
|
||||
// Register BasisTextureLoader for .basis extension.
|
||||
|
||||
if (!etcSupported && !dxtSupported && !pvrtcSupported) {
|
||||
log('No suitable compressed texture format supported!!');
|
||||
return;
|
||||
}
|
||||
THREE.Loader.Handlers.add( /\.basis$/, basisLoader );
|
||||
|
||||
let format = etcSupported ? BASIS_FORMAT.cTFETC1 : (dxtSupported ? BASIS_FORMAT.cTFBC1 : BASIS_FORMAT.cTFPVRTC1_4_OPAQUE_ONLY);
|
||||
// Create GLTFLoader, load model, and render.
|
||||
|
||||
log('Transcode to Compressed Texture Format: <strong>' + BASIS_FORMAT_NAMES[format] + '</strong>');
|
||||
const loader = new THREE.GLTFLoader();
|
||||
|
||||
class BasisTextureLoader {
|
||||
constructor() {
|
||||
this.count = 0;
|
||||
}
|
||||
loader.load( 'AGI_HQ/AgiHQ.gltf', ( gltf ) => {
|
||||
|
||||
load(url, onLoad, onProgress, onError) {
|
||||
const model = gltf.scene;
|
||||
model.scale.set( 0.01, 0.01, 0.01 );
|
||||
|
||||
fetch(url).then(res => res.arrayBuffer()).then(buf => {
|
||||
scene.add( model );
|
||||
|
||||
log('<strong> Texture ' + (this.count++) + '</strong>');
|
||||
document.body.appendChild( renderer.domElement );
|
||||
|
||||
const startTime = performance.now();
|
||||
animate();
|
||||
|
||||
const basisFile = new BasisFile(new Uint8Array(buf));
|
||||
}, undefined, ( e ) => console.error( e ) );
|
||||
|
||||
const width = basisFile.getImageWidth(0, 0);
|
||||
const height = basisFile.getImageHeight(0, 0);
|
||||
const images = basisFile.getNumImages();
|
||||
const levels = basisFile.getNumLevels(0);
|
||||
// Main render loop.
|
||||
|
||||
if (!width || !height || !images || !levels) {
|
||||
console.warn('Invalid .basis file');
|
||||
basisFile.close();
|
||||
basisFile.delete();
|
||||
return;
|
||||
}
|
||||
function animate() {
|
||||
|
||||
if (!basisFile.startTranscoding()) {
|
||||
console.warn('startTranscoding failed');
|
||||
basisFile.close();
|
||||
basisFile.delete();
|
||||
return;
|
||||
}
|
||||
requestAnimationFrame( animate );
|
||||
controls.update();
|
||||
renderer.render( scene, camera );
|
||||
|
||||
const dst = new Uint8Array(basisFile.getImageTranscodedSizeInBytes(0, 0, format));
|
||||
}
|
||||
|
||||
if (!basisFile.transcodeImage(dst, 0, 0, format, etcSupported ? 0 : (dxtSupported ? 1 : 0), 0)) {
|
||||
console.warn('transcodeImage failed');
|
||||
basisFile.close();
|
||||
basisFile.delete();
|
||||
return;
|
||||
}
|
||||
// Support viewport resizing.
|
||||
|
||||
const elapsed = performance.now() - startTime;
|
||||
window.addEventListener( 'resize', () => {
|
||||
|
||||
basisFile.close();
|
||||
basisFile.delete();
|
||||
camera.aspect = window.innerWidth / window.innerHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize( window.innerWidth, window.innerHeight );
|
||||
|
||||
console.log('Transcode success!', dst);
|
||||
console.log('Time:', elapsed, 'ms');
|
||||
}, false );
|
||||
|
||||
logTime('Transcode Time: ', elapsed);
|
||||
}
|
||||
|
||||
const mipmaps = [ { data: dst, width, height } ];
|
||||
let texture;
|
||||
if (etcSupported) {
|
||||
texture = new THREE.CompressedTexture( mipmaps, width, height, THREE.RGB_ETC1_Format );
|
||||
} else if (dxtSupported) {
|
||||
const type = dxtSupported ? THREE.UnsignedByteType : THREE.UnsignedShort565Type;
|
||||
const f = dxtSupported ? DXT_FORMAT_MAP[ format ] : THREE.RGBFormat;
|
||||
texture = new THREE.CompressedTexture( mipmaps, width, height, f, type );
|
||||
} else if (pvrtcSupported) {
|
||||
texture = new THREE.CompressedTexture( mipmaps, width, height, THREE.RGB_PVRTC_4BPPV1_Format );
|
||||
}
|
||||
function log(s) {
|
||||
|
||||
texture.minFilter = THREE.LinearFilter;
|
||||
texture.magFilter = THREE.LinearFilter;
|
||||
texture.encoding = THREE.sRGBEncoding;
|
||||
texture.generateMipmaps = false;
|
||||
texture.flipY = false;
|
||||
texture.needsUpdate = true;
|
||||
const div = document.createElement('div');
|
||||
div.innerHTML = s;
|
||||
document.getElementById('log').appendChild(div);
|
||||
|
||||
onLoad( texture );
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
THREE.Loader.Handlers.add(/\.basis$/, new BasisTextureLoader());
|
||||
|
||||
const loader = new THREE.GLTFLoader();
|
||||
|
||||
function animate() {
|
||||
requestAnimationFrame(animate);
|
||||
controls.update();
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
|
||||
loader.load('AGI_HQ/AgiHQ.gltf', (gltf) => {
|
||||
|
||||
const model = gltf.scene;
|
||||
model.scale.set(0.01, 0.01, 0.01);
|
||||
|
||||
const bbox = new THREE.Box3();
|
||||
bbox.setFromObject(model);
|
||||
console.log(bbox);
|
||||
|
||||
scene.add(model);
|
||||
|
||||
document.body.appendChild(renderer.domElement);
|
||||
|
||||
animate();
|
||||
|
||||
}, undefined, (e) => console.error(e));
|
||||
|
||||
}());
|
||||
}
|
||||
</script>
|
||||
<div id="pannel">
|
||||
<div id="panel">
|
||||
<strong>Basis Texture Transcoder glTF Demo</strong>
|
||||
<div id="log"></div>
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
Three.js
|
||||
|
||||
> The MIT License
|
||||
|
||||
Copyright © 2010-2019 three.js authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
Reference in New Issue
Block a user