瀏覽代碼

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js

David Catuhe 6 年之前
父節點
當前提交
ac058a266d

+ 1 - 0
dist/preview release/what's new.md

@@ -138,6 +138,7 @@
 - Skinned meshes now behave as intended by glTF ([bghgary](https://github.com/bghgary))
   - Skinned meshes now set an override mesh instead of reparenting to the `__root__` transform node
   - Loaded bones are linked with the transform node created for the corresponding glTF node
+- Add `EquiRectangularCubeTexture` class to enable the usage of browser-canvas supported images as `CubeTexture`'s ([Dennis Dervisis](https://github.com/ddervisis))
 
 ### glTF Serializer
 

+ 202 - 0
src/Materials/Textures/equiRectangularCubeTexture.ts

@@ -0,0 +1,202 @@
+import { PanoramaToCubeMapTools } from '../../Misc/HighDynamicRange/panoramaToCubemap';
+import { Engine } from "../../Engines/engine";
+import { BaseTexture } from './baseTexture';
+import { Texture } from './texture';
+import { Scene } from "../../scene";
+import { Nullable } from "../../types";
+
+/**
+ * This represents a texture coming from an equirectangular image supported by the web browser canvas.
+ */
+export class EquiRectangularCubeTexture extends BaseTexture {
+    /** The six faces of the cube. */
+    private static _FacesMapping = ['right', 'left', 'up', 'down', 'front', 'back'];
+
+    private _noMipmap: boolean;
+    private _onLoad: Nullable<() => void> = null;
+    private _onError: Nullable<() => void> = null;
+
+    /** The size of the cubemap. */
+    private _size: number;
+
+    /** The buffer of the image. */
+    private _buffer: ArrayBuffer;
+
+    /** The width of the input image. */
+    private _width: number;
+
+    /** The height of the input image. */
+    private _height: number;
+
+    /** The URL to the image. */
+    public url: string;
+
+    /** The texture coordinates mode. As this texture is stored in a cube format, please modify carefully. */
+    public coordinatesMode = Texture.CUBIC_MODE;
+
+    /**
+     * Instantiates an EquiRectangularCubeTexture from the following parameters.
+     * @param url The location of the image
+     * @param scene The scene the texture will be used in
+     * @param size The cubemap desired size (the more it increases the longer the generation will be)
+     * @param noMipmap Forces to not generate the mipmap if true
+     * @param gammaSpace Specifies if the texture will be used in gamma or linear space
+     * (the PBR material requires those textures in linear space, but the standard material would require them in Gamma space)
+     * @param onLoad — defines a callback called when texture is loaded
+     * @param onError — defines a callback called if there is an error
+     */
+    constructor(
+        url: string,
+        scene: Scene,
+        size: number,
+        noMipmap: boolean = false,
+        gammaSpace: boolean = true,
+        onLoad: Nullable<() => void> = null,
+        onError: Nullable<(message?: string, exception?: any) => void> = null
+    ) {
+        super(scene);
+
+        if (!url) {
+            throw new Error('Image url is not set');
+        }
+
+        this.name = url;
+        this.url = url;
+        this._size = size;
+        this._noMipmap = noMipmap;
+        this.gammaSpace = gammaSpace;
+        this._onLoad = onLoad;
+        this._onError = onError;
+
+        this.hasAlpha = false;
+        this.isCube = true;
+
+        this._texture = this._getFromCache(url, this._noMipmap);
+
+        if (!this._texture) {
+            if (!scene.useDelayedTextureLoading) {
+                this.loadImage(this.loadTexture.bind(this));
+            } else {
+                this.delayLoadState = Engine.DELAYLOADSTATE_NOTLOADED;
+            }
+        }
+    }
+
+    /**
+     * Load the image data, by putting the image on a canvas and extracting its buffer.
+     */
+    private loadImage(loadTextureCallback: () => void): void {
+        const canvas = document.createElement('canvas');
+        const image = new Image();
+
+        image.addEventListener('load', () => {
+            this._width = image.width;
+            this._height = image.height;
+            canvas.width = this._width;
+            canvas.height = this._height;
+
+            const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
+            ctx.drawImage(image, 0, 0);
+
+            const imageData = ctx.getImageData(0, 0, image.width, image.height);
+            this._buffer = imageData.data.buffer as ArrayBuffer;
+
+            canvas.remove();
+            loadTextureCallback();
+        });
+        image.src = this.url;
+    }
+
+    /**
+     * Convert the image buffer into a cubemap and create a CubeTexture.
+     */
+    private loadTexture(): void {
+        const scene = this.getScene();
+        const callback = (): Nullable<ArrayBufferView[]> => {
+            const imageData = this.getFloat32ArrayFromArrayBuffer(this._buffer);
+
+            // Extract the raw linear data.
+            const data = PanoramaToCubeMapTools.ConvertPanoramaToCubemap(imageData, this._width, this._height, this._size);
+
+            const results = [];
+
+            // Push each faces.
+            for (let i = 0; i < 6; i++) {
+                const dataFace = (data as any)[EquiRectangularCubeTexture._FacesMapping[i]];
+                results.push(dataFace);
+            }
+
+            return results;
+        };
+
+        if (!scene) {
+            return;
+        }
+        this._texture = scene
+            .getEngine()
+            .createRawCubeTextureFromUrl(
+                this.url,
+                scene,
+                this._size,
+                Engine.TEXTUREFORMAT_RGB,
+                scene.getEngine().getCaps().textureFloat
+                    ? Engine.TEXTURETYPE_FLOAT
+                    : Engine.TEXTURETYPE_UNSIGNED_INTEGER,
+                this._noMipmap,
+                callback,
+                null,
+                this._onLoad,
+                this._onError
+            );
+    }
+
+    /**
+     * Convert the ArrayBuffer into a Float32Array and drop the transparency channel.
+     * @param buffer The ArrayBuffer that should be converted.
+     * @returns The buffer as Float32Array.
+     */
+    private getFloat32ArrayFromArrayBuffer(buffer: ArrayBuffer): Float32Array {
+        const dataView = new DataView(buffer);
+        const floatImageData = new Float32Array((buffer.byteLength * 3) / 4);
+
+        let k = 0;
+        for (let i = 0; i < buffer.byteLength; i++) {
+            // We drop the transparency channel, because we do not need/want it
+            if ((i + 1) % 4 !== 0) {
+                floatImageData[k++] = dataView.getUint8(i) / 255;
+            }
+        }
+
+        return floatImageData;
+    }
+
+    /**
+     * Get the current class name of the texture useful for serialization or dynamic coding.
+     * @returns "EquiRectangularCubeTexture"
+     */
+    public getClassName(): string {
+        return "EquiRectangularCubeTexture";
+    }
+
+    /**
+     * Create a clone of the current EquiRectangularCubeTexture and return it.
+     * @returns A clone of the current EquiRectangularCubeTexture.
+     */
+    public clone(): EquiRectangularCubeTexture {
+        const scene = this.getScene();
+        if (!scene) {
+            return this;
+        }
+
+        const newTexture = new EquiRectangularCubeTexture(this.url, scene, this._size, this._noMipmap, this.gammaSpace);
+
+        // Base texture
+        newTexture.level = this.level;
+        newTexture.wrapU = this.wrapU;
+        newTexture.wrapV = this.wrapV;
+        newTexture.coordinatesIndex = this.coordinatesIndex;
+        newTexture.coordinatesMode = this.coordinatesMode;
+
+        return newTexture;
+    }
+}

+ 2 - 1
src/Materials/Textures/index.ts

@@ -2,6 +2,7 @@ export * from "./baseTexture";
 export * from "./colorGradingTexture";
 export * from "./cubeTexture";
 export * from "./dynamicTexture";
+export * from "./equiRectangularCubeTexture";
 export * from "./hdrCubeTexture";
 export * from "./internalTexture";
 export * from "./internalTextureLoader";
@@ -16,4 +17,4 @@ export * from "./rawTexture3D";
 export * from "./refractionTexture";
 export * from "./renderTargetTexture";
 export * from "./texture";
-export * from "./videoTexture";
+export * from "./videoTexture";