|
@@ -1,12 +1,13 @@
|
|
|
import { Scalar } from "../Maths/math.scalar";
|
|
|
import { SphericalPolynomial } from "../Maths/sphericalPolynomial";
|
|
|
import { Constants } from "../Engines/constants";
|
|
|
+import { Engine } from "../Engines/engine";
|
|
|
import { InternalTexture } from "../Materials/Textures/internalTexture";
|
|
|
import { Nullable } from "../types";
|
|
|
import { Logger } from "../Misc/logger";
|
|
|
import { CubeMapToSphericalPolynomialTools } from "../Misc/HighDynamicRange/cubemapToSphericalPolynomial";
|
|
|
-
|
|
|
-declare type Engine = import("../Engines/engine").Engine;
|
|
|
+import { Scene } from '../scene';
|
|
|
+import { BaseTexture } from '../Materials/Textures/baseTexture';
|
|
|
|
|
|
// Based on demo done by Brandon Jones - http://media.tojicode.com/webgl-samples/dds.html
|
|
|
// All values and structures referenced from:
|
|
@@ -650,3 +651,136 @@ declare type Engine = import("../Engines/engine").Engine;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ declare module "../Engines/engine" {
|
|
|
+ export interface Engine {
|
|
|
+ /**
|
|
|
+ * Create a cube texture from prefiltered data (ie. the mipmaps contain ready to use data for PBR reflection)
|
|
|
+ * @param rootUrl defines the url where the file to load is located
|
|
|
+ * @param scene defines the current scene
|
|
|
+ * @param lodScale defines scale to apply to the mip map selection
|
|
|
+ * @param lodOffset defines offset to apply to the mip map selection
|
|
|
+ * @param onLoad defines an optional callback raised when the texture is loaded
|
|
|
+ * @param onError defines an optional callback raised if there is an issue to load the texture
|
|
|
+ * @param format defines the format of the data
|
|
|
+ * @param forcedExtension defines the extension to use to pick the right loader
|
|
|
+ * @param createPolynomials defines wheter or not to create polynomails harmonics for the texture
|
|
|
+ * @returns the cube texture as an InternalTexture
|
|
|
+ */
|
|
|
+ createPrefilteredCubeTexture(rootUrl: string, scene: Nullable<Scene>, lodScale: number, lodOffset: number,
|
|
|
+ onLoad?: Nullable<(internalTexture: Nullable<InternalTexture>) => void>,
|
|
|
+ onError?: Nullable<(message?: string, exception?: any) => void>,
|
|
|
+ format?: number, forcedExtension?: any,
|
|
|
+ createPolynomials?: boolean): InternalTexture;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Create a cube texture from prefiltered data (ie. the mipmaps contain ready to use data for PBR reflection)
|
|
|
+ * @param rootUrl defines the url where the file to load is located
|
|
|
+ * @param scene defines the current scene
|
|
|
+ * @param lodScale defines scale to apply to the mip map selection
|
|
|
+ * @param lodOffset defines offset to apply to the mip map selection
|
|
|
+ * @param onLoad defines an optional callback raised when the texture is loaded
|
|
|
+ * @param onError defines an optional callback raised if there is an issue to load the texture
|
|
|
+ * @param format defines the format of the data
|
|
|
+ * @param forcedExtension defines the extension to use to pick the right loader
|
|
|
+ * @param createPolynomials defines wheter or not to create polynomails harmonics for the texture
|
|
|
+ * @returns the cube texture as an InternalTexture
|
|
|
+ */
|
|
|
+ Engine.prototype.createPrefilteredCubeTexture = function(rootUrl: string, scene: Nullable<Scene>, lodScale: number, lodOffset: number,
|
|
|
+ onLoad: Nullable<(internalTexture: Nullable<InternalTexture>) => void> = null,
|
|
|
+ onError: Nullable<(message?: string, exception?: any) => void> = null,
|
|
|
+ format?: number, forcedExtension: any = null,
|
|
|
+ createPolynomials: boolean = true): InternalTexture {
|
|
|
+ var callback = (loadData: any) => {
|
|
|
+ if (!loadData) {
|
|
|
+ if (onLoad) {
|
|
|
+ onLoad(null);
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ let texture = loadData.texture as InternalTexture;
|
|
|
+ if (!createPolynomials) {
|
|
|
+ texture._sphericalPolynomial = new SphericalPolynomial();
|
|
|
+ }
|
|
|
+ else if (loadData.info.sphericalPolynomial) {
|
|
|
+ texture._sphericalPolynomial = loadData.info.sphericalPolynomial;
|
|
|
+ }
|
|
|
+ texture._dataSource = InternalTexture.DATASOURCE_CUBEPREFILTERED;
|
|
|
+
|
|
|
+ if (this.getCaps().textureLOD) {
|
|
|
+ // Do not add extra process if texture lod is supported.
|
|
|
+ if (onLoad) {
|
|
|
+ onLoad(texture);
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const mipSlices = 3;
|
|
|
+
|
|
|
+ var gl = this._gl;
|
|
|
+ const width = loadData.width;
|
|
|
+ if (!width) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const textures: BaseTexture[] = [];
|
|
|
+ for (let i = 0; i < mipSlices; i++) {
|
|
|
+ //compute LOD from even spacing in smoothness (matching shader calculation)
|
|
|
+ let smoothness = i / (mipSlices - 1);
|
|
|
+ let roughness = 1 - smoothness;
|
|
|
+
|
|
|
+ let minLODIndex = lodOffset; // roughness = 0
|
|
|
+ let maxLODIndex = Scalar.Log2(width) * lodScale + lodOffset; // roughness = 1
|
|
|
+
|
|
|
+ let lodIndex = minLODIndex + (maxLODIndex - minLODIndex) * roughness;
|
|
|
+ let mipmapIndex = Math.round(Math.min(Math.max(lodIndex, 0), maxLODIndex));
|
|
|
+
|
|
|
+ var glTextureFromLod = new InternalTexture(this, InternalTexture.DATASOURCE_TEMP);
|
|
|
+ glTextureFromLod.type = texture.type;
|
|
|
+ glTextureFromLod.format = texture.format;
|
|
|
+ glTextureFromLod.width = Math.pow(2, Math.max(Scalar.Log2(width) - mipmapIndex, 0));
|
|
|
+ glTextureFromLod.height = glTextureFromLod.width;
|
|
|
+ glTextureFromLod.isCube = true;
|
|
|
+ this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, glTextureFromLod, true);
|
|
|
+
|
|
|
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
|
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
|
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
|
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
|
+
|
|
|
+ if (loadData.isDDS) {
|
|
|
+ var info: DDSInfo = loadData.info;
|
|
|
+ var data: any = loadData.data;
|
|
|
+ this._unpackFlipY(info.isCompressed);
|
|
|
+
|
|
|
+ DDSTools.UploadDDSLevels(this, glTextureFromLod, data, info, true, 6, mipmapIndex);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ Logger.Warn("DDS is the only prefiltered cube map supported so far.");
|
|
|
+ }
|
|
|
+
|
|
|
+ this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, null);
|
|
|
+
|
|
|
+ // Wrap in a base texture for easy binding.
|
|
|
+ const lodTexture = new BaseTexture(scene);
|
|
|
+ lodTexture.isCube = true;
|
|
|
+ lodTexture._texture = glTextureFromLod;
|
|
|
+
|
|
|
+ glTextureFromLod.isReady = true;
|
|
|
+ textures.push(lodTexture);
|
|
|
+ }
|
|
|
+
|
|
|
+ texture._lodTextureHigh = textures[2];
|
|
|
+ texture._lodTextureMid = textures[1];
|
|
|
+ texture._lodTextureLow = textures[0];
|
|
|
+
|
|
|
+ if (onLoad) {
|
|
|
+ onLoad(texture);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ return this.createCubeTexture(rootUrl, scene, null, false, callback, onError, format, forcedExtension, createPolynomials, lodScale, lodOffset);
|
|
|
+ };
|