123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333 |
- import { Vector3, Tools } from "babylonjs";
- import { TextureCube, PixelFormat, PixelType } from './texture';
- /**
- * Spherical polynomial coefficients (counter part to spherical harmonic coefficients used in shader irradiance calculation)
- * @ignoreChildren
- */
- export interface SphericalPolynomalCoefficients {
- x: Vector3;
- y: Vector3;
- z: Vector3;
- xx: Vector3;
- yy: Vector3;
- zz: Vector3;
- yz: Vector3;
- zx: Vector3;
- xy: Vector3;
- }
- /**
- * Wraps data and maps required for environments with physically based rendering
- */
- export interface PBREnvironment {
- /**
- * Spherical Polynomial Coefficients representing an irradiance map
- */
- irradiancePolynomialCoefficients: SphericalPolynomalCoefficients;
- /**
- * Specular cubemap
- */
- specularTexture?: TextureCube;
- /**
- * A scale factor applied to RGB values after reading from environment maps
- */
- textureIntensityScale: number;
- }
- /**
- * Environment map representations: layouts, projections and approximations
- */
- export type MapType =
- 'irradiance_sh_coefficients_9' |
- 'cubemap_faces';
- /**
- * Image type used for environment map
- */
- export type ImageType = 'png';
- //Payload Descriptor
- /**
- * A generic field in JSON that report's its type
- */
- export interface TypedObject<T> {
- type: T;
- }
- /**
- * Describes a range of bytes starting at byte pos (inclusive) and finishing at byte pos + length - 1
- */
- export interface ByteRange {
- pos: number;
- length: number;
- }
- /**
- * Complete Spectre Environment JSON Descriptor
- */
- export interface EnvJsonDescriptor {
- radiance: TypedObject<MapType>;
- irradiance: TypedObject<MapType>;
- specular: TypedObject<MapType>;
- }
- /**
- * Spherical harmonic coefficients to provide an irradiance map
- */
- export interface IrradianceSHCoefficients9 extends TypedObject<MapType> {
- l00: Array<number>;
- l1_1: Array<number>;
- l10: Array<number>;
- l11: Array<number>;
- l2_2: Array<number>;
- l2_1: Array<number>;
- l20: Array<number>;
- l21: Array<number>;
- l22: Array<number>;
- }
- /**
- * A generic set of images, where the image content is specified by byte ranges in the mipmaps field
- */
- export interface ImageSet<T> extends TypedObject<MapType> {
- imageType: ImageType;
- width: number;
- height: number;
- mipmaps: Array<T>;
- multiplier: number;
- }
- /**
- * A set of cubemap faces
- */
- export type CubemapFaces = ImageSet<Array<ByteRange>>;
- /**
- * A single image containing an atlas of equirectangular-projection maps across all mip levels
- */
- export type EquirectangularMipmapAtlas = ImageSet<ByteRange>;
- /**
- * A static class proving methods to aid parsing Spectre environment files
- */
- export class EnvironmentDeserializer {
- /**
- * Parses an arraybuffer into a new PBREnvironment object
- * @param arrayBuffer The arraybuffer of the Spectre environment file
- * @return a PBREnvironment object
- */
- public static Parse(arrayBuffer: ArrayBuffer): PBREnvironment {
- var environment: PBREnvironment = {
- //irradiance
- irradiancePolynomialCoefficients: {
- x: new Vector3(0, 0, 0),
- y: new Vector3(0, 0, 0),
- z: new Vector3(0, 0, 0),
- xx: new Vector3(0, 0, 0),
- yy: new Vector3(0, 0, 0),
- zz: new Vector3(0, 0, 0),
- yz: new Vector3(0, 0, 0),
- zx: new Vector3(0, 0, 0),
- xy: new Vector3(0, 0, 0)
- },
- //specular
- textureIntensityScale: 1.0,
- };
- //read .env
- let littleEndian = false;
- let magicBytes = [0x86, 0x16, 0x87, 0x96, 0xf6, 0xd6, 0x96, 0x36];
- let dataView = new DataView(arrayBuffer);
- let pos = 0;
- for (let i = 0; i < magicBytes.length; i++) {
- if (dataView.getUint8(pos++) !== magicBytes[i]) {
- Tools.Error('Not a Spectre environment map');
- }
- }
- let version = dataView.getUint16(pos, littleEndian); pos += 2;
- if (version !== 1) {
- Tools.Warn('Unsupported Spectre environment map version "' + version + '"');
- }
- //read json descriptor - collect characters up to null terminator
- let descriptorString = '';
- let charCode = 0x00;
- while ((charCode = dataView.getUint8(pos++))) {
- descriptorString += String.fromCharCode(charCode);
- }
- let descriptor: EnvJsonDescriptor = JSON.parse(descriptorString);
- let payloadPos = pos;
- //irradiance
- switch (descriptor.irradiance.type) {
- case 'irradiance_sh_coefficients_9':
- //irradiance
- let harmonics = <IrradianceSHCoefficients9>descriptor.irradiance;
- EnvironmentDeserializer._ConvertSHIrradianceToLambertianRadiance(harmonics);
- //harmonics now represent radiance
- EnvironmentDeserializer._ConvertSHToSP(harmonics, environment.irradiancePolynomialCoefficients);
- break;
- default:
- Tools.Error('Unhandled MapType descriptor.irradiance.type (' + descriptor.irradiance.type + ')');
- }
- //specular
- switch (descriptor.specular.type) {
- case 'cubemap_faces':
- var specularDescriptor = <CubemapFaces>descriptor.specular;
- let specularTexture = environment.specularTexture = new TextureCube(PixelFormat.RGBA, PixelType.UNSIGNED_BYTE);
- environment.textureIntensityScale = specularDescriptor.multiplier != null ? specularDescriptor.multiplier : 1.0;
- let mipmaps = specularDescriptor.mipmaps;
- let imageType = specularDescriptor.imageType;
- for (let l = 0; l < mipmaps.length; l++) {
- let faceRanges = mipmaps[l];
- specularTexture.source[l] = [];
- for (let i = 0; i < 6; i++) {
- let range = faceRanges[i];
- let bytes = new Uint8Array(arrayBuffer, payloadPos + range.pos, range.length);
- switch (imageType) {
- case 'png':
- //construct image element from bytes
- let image = new Image();
- let src = URL.createObjectURL(new Blob([bytes], { type: 'image/png' }));
- image.src = src;
- specularTexture.source[l][i] = image;
- break;
- default:
- Tools.Error('Unhandled ImageType descriptor.specular.imageType (' + imageType + ')');
- }
- }
- }
- break;
- default:
- Tools.Error('Unhandled MapType descriptor.specular.type (' + descriptor.specular.type + ')');
- }
- return environment;
- }
- /**
- * Convert from irradiance to outgoing radiance for Lambertian BDRF, suitable for efficient shader evaluation.
- * L = (1/pi) * E * rho
- *
- * This is done by an additional scale by 1/pi, so is a fairly trivial operation but important conceptually.
- * @param harmonics Spherical harmonic coefficients (9)
- */
- private static _ConvertSHIrradianceToLambertianRadiance(harmonics: any): void {
- EnvironmentDeserializer._ScaleSH(harmonics, 1 / Math.PI);
- // The resultant SH now represents outgoing radiance, so includes the Lambert 1/pi normalisation factor but without albedo (rho) applied
- // (The pixel shader must apply albedo after texture fetches, etc).
- }
- /**
- * Convert spherical harmonics to spherical polynomial coefficients
- * @param harmonics Spherical harmonic coefficients (9)
- * @param outPolynomialCoefficents Polynomial coefficients (9) object to store result
- */
- private static _ConvertSHToSP(harmonics: any, outPolynomialCoefficents: SphericalPolynomalCoefficients) {
- const rPi = 1 / Math.PI;
- //x
- outPolynomialCoefficents.x.x = 1.02333 * harmonics.l11[0] * rPi;
- outPolynomialCoefficents.x.y = 1.02333 * harmonics.l11[1] * rPi;
- outPolynomialCoefficents.x.z = 1.02333 * harmonics.l11[2] * rPi;
- outPolynomialCoefficents.y.x = 1.02333 * harmonics.l1_1[0] * rPi;
- outPolynomialCoefficents.y.y = 1.02333 * harmonics.l1_1[1] * rPi;
- outPolynomialCoefficents.y.z = 1.02333 * harmonics.l1_1[2] * rPi;
- outPolynomialCoefficents.z.x = 1.02333 * harmonics.l10[0] * rPi;
- outPolynomialCoefficents.z.y = 1.02333 * harmonics.l10[1] * rPi;
- outPolynomialCoefficents.z.z = 1.02333 * harmonics.l10[2] * rPi;
- //xx
- outPolynomialCoefficents.xx.x = (0.886277 * harmonics.l00[0] - 0.247708 * harmonics.l20[0] + 0.429043 * harmonics.l22[0]) * rPi;
- outPolynomialCoefficents.xx.y = (0.886277 * harmonics.l00[1] - 0.247708 * harmonics.l20[1] + 0.429043 * harmonics.l22[1]) * rPi;
- outPolynomialCoefficents.xx.z = (0.886277 * harmonics.l00[2] - 0.247708 * harmonics.l20[2] + 0.429043 * harmonics.l22[2]) * rPi;
- outPolynomialCoefficents.yy.x = (0.886277 * harmonics.l00[0] - 0.247708 * harmonics.l20[0] - 0.429043 * harmonics.l22[0]) * rPi;
- outPolynomialCoefficents.yy.y = (0.886277 * harmonics.l00[1] - 0.247708 * harmonics.l20[1] - 0.429043 * harmonics.l22[1]) * rPi;
- outPolynomialCoefficents.yy.z = (0.886277 * harmonics.l00[2] - 0.247708 * harmonics.l20[2] - 0.429043 * harmonics.l22[2]) * rPi;
- outPolynomialCoefficents.zz.x = (0.886277 * harmonics.l00[0] + 0.495417 * harmonics.l20[0]) * rPi;
- outPolynomialCoefficents.zz.y = (0.886277 * harmonics.l00[1] + 0.495417 * harmonics.l20[1]) * rPi;
- outPolynomialCoefficents.zz.z = (0.886277 * harmonics.l00[2] + 0.495417 * harmonics.l20[2]) * rPi;
- //yz
- outPolynomialCoefficents.yz.x = 0.858086 * harmonics.l2_1[0] * rPi;
- outPolynomialCoefficents.yz.y = 0.858086 * harmonics.l2_1[1] * rPi;
- outPolynomialCoefficents.yz.z = 0.858086 * harmonics.l2_1[2] * rPi;
- outPolynomialCoefficents.zx.x = 0.858086 * harmonics.l21[0] * rPi;
- outPolynomialCoefficents.zx.y = 0.858086 * harmonics.l21[1] * rPi;
- outPolynomialCoefficents.zx.z = 0.858086 * harmonics.l21[2] * rPi;
- outPolynomialCoefficents.xy.x = 0.858086 * harmonics.l2_2[0] * rPi;
- outPolynomialCoefficents.xy.y = 0.858086 * harmonics.l2_2[1] * rPi;
- outPolynomialCoefficents.xy.z = 0.858086 * harmonics.l2_2[2] * rPi;
- }
- /**
- * Multiplies harmonic coefficients in place
- * @param harmonics Spherical harmonic coefficients (9)
- * @param scaleFactor Value to multiply by
- */
- private static _ScaleSH(harmonics: any, scaleFactor: number) {
- harmonics.l00[0] *= scaleFactor;
- harmonics.l00[1] *= scaleFactor;
- harmonics.l00[2] *= scaleFactor;
- harmonics.l1_1[0] *= scaleFactor;
- harmonics.l1_1[1] *= scaleFactor;
- harmonics.l1_1[2] *= scaleFactor;
- harmonics.l10[0] *= scaleFactor;
- harmonics.l10[1] *= scaleFactor;
- harmonics.l10[2] *= scaleFactor;
- harmonics.l11[0] *= scaleFactor;
- harmonics.l11[1] *= scaleFactor;
- harmonics.l11[2] *= scaleFactor;
- harmonics.l2_2[0] *= scaleFactor;
- harmonics.l2_2[1] *= scaleFactor;
- harmonics.l2_2[2] *= scaleFactor;
- harmonics.l2_1[0] *= scaleFactor;
- harmonics.l2_1[1] *= scaleFactor;
- harmonics.l2_1[2] *= scaleFactor;
- harmonics.l20[0] *= scaleFactor;
- harmonics.l20[1] *= scaleFactor;
- harmonics.l20[2] *= scaleFactor;
- harmonics.l21[0] *= scaleFactor;
- harmonics.l21[1] *= scaleFactor;
- harmonics.l21[2] *= scaleFactor;
- harmonics.l22[0] *= scaleFactor;
- harmonics.l22[1] *= scaleFactor;
- harmonics.l22[2] *= scaleFactor;
- }
- }
|