threepipe
Version:
A 3D viewer framework built on top of three.js in TypeScript with a focus on quality rendering, modularity and extensibility.
76 lines • 3.51 kB
JavaScript
import { DataTexture, DataUtils, FileLoader, FloatType, HalfFloatType, LinearFilter, RGBAFormat, SRGBColorSpace, } from 'three';
import { imageUrlToImageData } from 'ts-browser-helpers';
/**
* 8bit HDR image in png format
* not properly working with files from hdrpng.js but used in {@link GLTFViewerConfigExtension}, so a slightly modified version is used here
*/
export class RGBEPNGLoader extends FileLoader {
constructor(manager) {
super(manager);
this.type = HalfFloatType;
}
async loadAsync(url, onProgress) {
const image = await this.parseAsync(url, onProgress, false);
const texture = new DataTexture(image.data, image.width, image.height, RGBAFormat, this.type);
texture.needsUpdate = true;
texture.flipY = true;
texture.colorSpace = SRGBColorSpace;
texture.minFilter = LinearFilter;
texture.magFilter = LinearFilter;
texture.source.data.complete = true;
return texture;
}
async parseAsync(url, onProgress, isFloat16Data = false) {
let created = false;
if (!url.startsWith('data:') && !url.startsWith('blob:')) {
this.responseType = 'blob';
const blob = await super.loadAsync(url, onProgress);
// url = await blobToDataURL(blob)
// console.log(url)
// url = url.replace('application/octet-stream', 'image/png')
url = URL.createObjectURL(blob);
created = true;
}
const imageData = await imageUrlToImageData(url);
if (created)
URL.revokeObjectURL(url);
let aType = Uint8Array;
if (this.type === HalfFloatType)
aType = Uint16Array;
else if (this.type === FloatType)
aType = Float32Array;
const buffer = rgbeToHalfFloat(imageData.data, 4, aType, isFloat16Data);
return { data: buffer, width: imageData.width, height: imageData.height };
}
setDataType(value) {
this.type = value;
return this;
}
}
// adapted from https://github.com/enkimute/hdrpng.js/blob/3a62b3ae2940189777df9f669df5ece3e78d9c16/hdrpng.js#L253
// channels = 4 for RGBA data or 3 for RGB data. res to use with THREE.DataTexture
function rgbeToHalfFloat(buffer, channels = 3, type = Uint16Array, float16Data = false) {
let s;
const l = buffer.byteLength >> 2;
const res = new type(l * channels);
for (let i = 0; i < l; i++) {
s = Math.pow(2, buffer[i * 4 + 3] - (128 + 8));
if (float16Data) {
res[i * channels] = Math.min(buffer[i * 4] * s, 65504);
res[i * channels + 1] = Math.min(buffer[i * 4 + 1] * s, 65504);
res[i * channels + 2] = Math.min(buffer[i * 4 + 2] * s, 65504);
}
else {
res[i * channels] = DataUtils.toHalfFloat(Math.min(buffer[i * 4] * s, 65504));
res[i * channels + 1] = DataUtils.toHalfFloat(Math.min(buffer[i * 4 + 1] * s, 65504));
res[i * channels + 2] = DataUtils.toHalfFloat(Math.min(buffer[i * 4 + 2] * s, 65504));
}
// res[i * channels] = Math.min(15360, buffer[i * 4] * s)
// res[i * channels + 1] = Math.min(15360, buffer[i * 4 + 1] * s)
// res[i * channels + 2] = Math.min(15360, buffer[i * 4 + 2] * s)
if (channels === 4)
res[i * channels + 3] = DataUtils.toHalfFloat(1); // alpha is always 1 // todo: handle for uint8 and float32
}
return res;
}
//# sourceMappingURL=RGBEPNGLoader.js.map