Sebastien Vandenberghe před 6 roky
rodič
revize
44db972af6

+ 1 - 0
Tools/DevLoader/BabylonLoader.js

@@ -206,6 +206,7 @@ var BABYLONDEVTOOLS;
                 else if (!coreOnly || module.isCore) {
                     this.loadLibrary(moduleName, module.libraries[i], module);
                 }
+                // Allow also loaders in CORE.
                 else if (coreOnly && moduleName === "loaders") {
                     this.loadLibrary(moduleName, module.libraries[i], module);
                 }

+ 15 - 3
src/Engines/WebGPU/webgpuPipelineContext.ts

@@ -1,22 +1,34 @@
 import { IPipelineContext } from '../IPipelineContext';
 import { Nullable } from '../../types';
 import { WebGPUEngine } from '../webgpuEngine';
+import { InternalTexture } from 'Materials';
+
+/** @hidden */
+export interface IWebGPUPipelineContext {
+    textureBinding: number;
+
+    samplerBinding: number;
+
+    texture: InternalTexture;
+}
 
 /** @hidden */
 export class WebGPUPipelineContext implements IPipelineContext {
     public engine: WebGPUEngine;
 
+    public vertexShaderCode: string;
+    public fragmentShaderCode: string;
     public stages: Nullable<GPURenderPipelineStageDescriptor>;
 
     // public vertexInputDescriptor: GPUVertexAttributeDescriptor[] = [];
 
-    public vertexShaderCode: string;
-    public fragmentShaderCode: string;
+    public bindGroupLayouts: (GPUBindGroupLayout | undefined)[];
 
     public renderPipeline: GPURenderPipeline;
 
-    public bindGroupLayouts: (GPUBindGroupLayout | undefined)[];
+    public samplers: { [name: string]: Nullable<IWebGPUPipelineContext> } = { };
 
+    // Default implementation.
     public onCompiled?: () => void;
 
     public get isAsync() {

+ 2 - 1
src/Engines/engine.ts

@@ -5363,8 +5363,9 @@ export class Engine {
      * @param channel The texture channel
      * @param uniform The uniform to set
      * @param texture The texture to apply
+     * @param name The name of the uniform in the effect
      */
-    public setTexture(channel: number, uniform: Nullable<WebGLUniformLocation>, texture: Nullable<BaseTexture>): void {
+    public setTexture(channel: number, uniform: Nullable<WebGLUniformLocation>, texture: Nullable<BaseTexture>, name: string): void {
         if (channel === undefined) {
             return;
         }

+ 475 - 112
src/Engines/webgpuEngine.ts

@@ -2,6 +2,7 @@ import { Logger } from "../Misc/logger";
 import { Nullable, DataArray, IndicesArray, FloatArray } from "../types";
 import { Scene } from "../scene";
 import { Matrix, Color3, Color4 } from "../Maths/math";
+import { Scalar } from "../Maths/math.scalar";
 import { Engine, EngineCapabilities } from "../Engines/engine";
 import { RenderTargetCreationOptions } from "../Materials/Textures/renderTargetCreationOptions";
 import { InternalTexture } from "../Materials/Textures/internalTexture";
@@ -15,6 +16,8 @@ import { WebGPUPipelineContext } from './WebGPU/webgpuPipelineContext';
 import { IPipelineContext } from './IPipelineContext';
 import { DataBuffer } from '../Meshes/dataBuffer';
 import { WebGPUDataBuffer } from '../Meshes/WebGPU/webgpuDataBuffer';
+import { IInternalTextureLoader } from "../Materials/Textures/internalTextureLoader";
+import { BaseTexture } from "../Materials/Textures/baseTexture";
 
 /**
  * Options to create the WebGPU engine
@@ -92,6 +95,14 @@ export class WebGPUEngine extends Engine {
     // Caches
     // private _compiledStages: { [key: string]: GPURenderPipelineStageDescriptor } = {};
 
+    // Temporary...
+    private _decodeCanvas = document.createElement("canvas");
+    private _decodeEngine = new Engine(this._decodeCanvas, false, {
+        alpha: true,
+        premultipliedAlpha: false,
+    }, false);
+    //private _decodeScene = new Scene(this._decodeEngine);
+
     /**
      * @see https://doc.babylonjs.com/babylon101/animations#deterministic-lockstep
      */
@@ -128,6 +139,11 @@ export class WebGPUEngine extends Engine {
     public constructor(canvas: HTMLCanvasElement, options: WebGPUEngineOptions = new WebGPUEngineOptions()) {
         super(null);
 
+        this._decodeEngine.getCaps().textureFloat = false;
+        this._decodeEngine.getCaps().textureFloatRender = false;
+        this._decodeEngine.getCaps().textureHalfFloat = false;
+        this._decodeEngine.getCaps().textureHalfFloatRender = false;
+
         Logger.Log(`Babylon.js v${Engine.Version} - WebGPU engine`);
         if (!navigator.gpu) {
             // ToDo Fall back to webgl.
@@ -209,13 +225,13 @@ export class WebGPUEngine extends Engine {
         this._caps.highPrecisionShaderSupported = true;
 
         this._caps.colorBufferFloat = true;
-        this._caps.textureFloat = true;
-        this._caps.textureFloatLinearFiltering = true;
-        this._caps.textureFloatRender = true;
+        this._caps.textureFloat = false;
+        this._caps.textureFloatLinearFiltering = false;
+        this._caps.textureFloatRender = false;
 
-        this._caps.textureHalfFloat = true;
-        this._caps.textureHalfFloatLinearFiltering = true;
-        this._caps.textureHalfFloatRender = true;
+        this._caps.textureHalfFloat = false;
+        this._caps.textureHalfFloatLinearFiltering = false;
+        this._caps.textureHalfFloatRender = false;
 
         this._caps.textureLOD = true;
         this._caps.drawBuffersExtension = true;
@@ -370,9 +386,24 @@ export class WebGPUEngine extends Engine {
     }
 
     //------------------------------------------------------------------------------
-    //                              Vertex/Index Buffers
+    //                              WebGPU Buffers
     //------------------------------------------------------------------------------
 
+    private _createBuffer(view: ArrayBufferView, flags: GPUBufferUsageFlags): DataBuffer {
+        const verticesBufferDescriptor = {
+            size: view.byteLength,
+            usage: flags
+        };
+        const buffer = this._device.createBuffer(verticesBufferDescriptor);
+        const dataBuffer = new WebGPUDataBuffer(buffer);
+        dataBuffer.references = 1;
+        dataBuffer.capacity = verticesBufferDescriptor.size;
+
+        this._setSubData(dataBuffer, 0, view);
+
+        return dataBuffer;
+    }
+
     private _setSubData(dataBuffer: WebGPUDataBuffer, dstByteOffset: number, src: ArrayBufferView, srcByteOffset = 0, byteLength = 0): void {
         const buffer = dataBuffer.underlyingResource as GPUBuffer;
 
@@ -381,14 +412,39 @@ export class WebGPUEngine extends Engine {
 
         // After Migration to Canary
         // This would do from PR #261
-        const falseStart = src.byteOffset + srcByteOffset;
+        let falseStart = src.byteOffset + srcByteOffset;
         const falseEnd = falseStart + byteLength;
-        const tempView = new Uint8Array(src.buffer.slice(falseStart, falseEnd));
-        buffer.setSubData(dstByteOffset, tempView.buffer);
+
+        // Chunk
+        const maxChunk = 1024 * 1024;
+        let offset = 0;
+
+        // if ((falseEnd - (falseStart + offset)) > maxChunk) {
+        //     var toto = new Uint8ClampedArray(src.buffer);
+        //     for (let i = 0; i < byteLength; i+=4) {
+        //         toto[i] = Math.ceil(i / byteLength * 255);
+        //         toto[i + 1] = Math.ceil(i / byteLength * 255);
+        //         toto[i + 2] = Math.ceil(i / byteLength * 255);
+        //         toto[i + 3] = 255;
+        //     }
+        // }
+
+        while ((falseEnd - (falseStart + offset)) > maxChunk) {
+            const tempView = new Uint8Array(src.buffer.slice(falseStart + offset, falseStart + offset + maxChunk));
+            buffer.setSubData(dstByteOffset + offset, tempView.buffer);
+            offset += maxChunk;
+        }
+        
+        const tempView = new Uint8Array(src.buffer.slice(falseStart + offset, falseEnd));
+        buffer.setSubData(dstByteOffset + offset, tempView.buffer);
 
         // buffer.setSubData(dstByteOffset, src, srcByteOffset, byteLength);
     }
 
+    //------------------------------------------------------------------------------
+    //                              Vertex/Index Buffers
+    //------------------------------------------------------------------------------
+
     public createVertexBuffer(data: DataArray): DataBuffer {
         let view: ArrayBufferView;
 
@@ -402,19 +458,7 @@ export class WebGPUEngine extends Engine {
             view = data;
         }
 
-        const verticesBufferDescriptor = {
-            size: view.byteLength,
-            usage: WebGPUConstants.GPUBufferUsage_VERTEX | WebGPUConstants.GPUBufferUsage_TRANSFER_DST
-        };
-
-        const verticesBuffer = this._device.createBuffer(verticesBufferDescriptor);
-
-        const dataBuffer = new WebGPUDataBuffer(verticesBuffer);
-        dataBuffer.references = 1;
-        dataBuffer.capacity = verticesBufferDescriptor.size;
-
-        this._setSubData(dataBuffer, 0, view);
-
+        const dataBuffer = this._createBuffer(view, WebGPUConstants.GPUBufferUsage_VERTEX | WebGPUConstants.GPUBufferUsage_TRANSFER_DST);
         return dataBuffer;
     }
 
@@ -484,20 +528,8 @@ export class WebGPUEngine extends Engine {
             }
         }
 
-        const indexBufferDescriptor = {
-            size: view.byteLength,
-            usage: WebGPUConstants.GPUBufferUsage_INDEX | WebGPUConstants.GPUBufferUsage_TRANSFER_DST
-        };
-
-        const indicesBuffer = this._device.createBuffer(indexBufferDescriptor);
-
-        const dataBuffer = new WebGPUDataBuffer(indicesBuffer);
-        dataBuffer.references = 1;
+        const dataBuffer = this._createBuffer(view, WebGPUConstants.GPUBufferUsage_INDEX | WebGPUConstants.GPUBufferUsage_TRANSFER_DST);
         dataBuffer.is32Bits = is32Bits;
-        dataBuffer.capacity = indexBufferDescriptor.size;
-
-        this._setSubData(dataBuffer, 0, view);
-
         return dataBuffer;
     }
 
@@ -575,19 +607,8 @@ export class WebGPUEngine extends Engine {
             view = elements;
         }
 
-        const uboDescriptor = {
-            size: view.byteLength,
-            usage: WebGPUConstants.GPUBufferUsage_UNIFORM | WebGPUConstants.GPUBufferUsage_TRANSFER_DST,
-        };
-        const ubo = this._device.createBuffer(uboDescriptor);
-
-        const result = new WebGPUDataBuffer(ubo);
-        result.capacity = uboDescriptor.size;
-        result.references = 1;
-
-        this.updateUniformBuffer(result, elements);
-
-        return result;
+        const dataBuffer = this._createBuffer(view, WebGPUConstants.GPUBufferUsage_UNIFORM | WebGPUConstants.GPUBufferUsage_TRANSFER_DST);
+        return dataBuffer;
     }
 
     /**
@@ -790,7 +811,8 @@ export class WebGPUEngine extends Engine {
 
             const attributeIndex = attributesNames.indexOf(name);
             if (attributeIndex === -1) {
-                throw "Required attribute not found in the shader.";
+                continue;
+                // throw "Required attribute not found in the shader.";
             }
 
             results[attributeIndex] = +location;
@@ -840,93 +862,294 @@ export class WebGPUEngine extends Engine {
 
     /** @hidden */
     public _releaseTexture(texture: InternalTexture): void {
+        // TODO. check if it is all to release.
+        if (texture._webGPUTexture) {
+            texture._webGPUTexture.destroy();
+        }
+    }
+
+    private _uploadMipMapsFromWebglTexture(mipMaps: number, webglEngineTexture: InternalTexture, gpuTexture: GPUTexture, width: number, height: number, face: number) {
+        this._uploadFromWebglTexture(webglEngineTexture, gpuTexture, width, height, face);
+        
+        let faceWidth = width;
+        let faceHeight = height;
+
+        for (let mip = 1; mip <= mipMaps; mip++) {
+            faceWidth = Math.max(Math.floor(faceWidth / 2), 1);
+            faceHeight = Math.max(Math.floor(faceHeight / 2), 1);
+
+            this._uploadFromWebglTexture(webglEngineTexture, gpuTexture, faceWidth, faceHeight, face, mip);
+        }
+    }
+
+    private _uploadFromWebglTexture(webglEngineTexture: InternalTexture, gpuTexture: GPUTexture, width: number, height: number, face: number, mip: number = 0): void {
+        let pixels = this._decodeEngine._readTexturePixels(webglEngineTexture, width, height, face, mip);
+        if (pixels instanceof Float32Array) {
+            const newPixels = new Uint8ClampedArray(pixels.length);
+            pixels.forEach((value, index) => newPixels[index] = value * 255);
+            pixels = newPixels;
+        }
+
+        const textureView: GPUTextureCopyView = {
+            texture: gpuTexture,
+            origin: { 
+                x: 0,
+                y: 0,
+                z: 0
+            },
+            mipLevel: mip,
+            arrayLayer: Math.max(face, 0),
+        };
+        const textureExtent = {
+            width,
+            height,
+            depth: 1
+        };
+
+        const commandEncoder = this._device.createCommandEncoder({});
+        const rowPitch = Math.ceil(width * 4 / 256) * 256;
+
+        let dataBuffer: DataBuffer;
+        if (rowPitch == width * 4) {
+            dataBuffer = this._createBuffer(pixels, WebGPUConstants.GPUBufferUsage_TRANSFER_SRC | WebGPUConstants.GPUBufferUsage_TRANSFER_DST);
+            const bufferView: GPUBufferCopyView = {
+                buffer: dataBuffer.underlyingResource,
+                rowPitch: rowPitch,
+                imageHeight: height,
+                offset: 0,
+            };
+            commandEncoder.copyBufferToTexture(bufferView, textureView, textureExtent);
+        } else {
+            const alignedPixels = new Uint8Array(rowPitch * height);
+            let pixelsIndex = 0;
+            for (let y = 0; y < height; ++y) {
+                for (let x = 0; x < width; ++x) {
+                    let i = x * 4 + y * rowPitch;
+
+                    alignedPixels[i] = (pixels as any)[pixelsIndex];
+                    alignedPixels[i + 1] = (pixels as any)[pixelsIndex + 1];
+                    alignedPixels[i + 2] = (pixels as any)[pixelsIndex + 2];
+                    alignedPixels[i + 3] = (pixels as any)[pixelsIndex + 3];
+                    pixelsIndex += 4;
+                }
+            }
+            dataBuffer = this._createBuffer(alignedPixels, WebGPUConstants.GPUBufferUsage_TRANSFER_SRC | WebGPUConstants.GPUBufferUsage_TRANSFER_DST);
+            const bufferView: GPUBufferCopyView = {
+                buffer: dataBuffer.underlyingResource,
+                rowPitch: rowPitch,
+                imageHeight: height,
+                offset: 0,
+            };
+            commandEncoder.copyBufferToTexture(bufferView, textureView, textureExtent);
+        }
+
+        this._device.getQueue().submit([commandEncoder.finish()]);
+
+        this._releaseBuffer(dataBuffer);
     }
 
     public createTexture(urlArg: string, noMipmap: boolean, invertY: boolean, scene: Scene, samplingMode: number = Constants.TEXTURE_TRILINEAR_SAMPLINGMODE, onLoad: Nullable<() => void> = null, onError: Nullable<(message: string, exception: any) => void> = null, buffer: Nullable<ArrayBuffer | HTMLImageElement> = null, fallBack?: InternalTexture, format?: number): InternalTexture {
-        var texture = new InternalTexture(this, InternalTexture.DATASOURCE_URL);
-        var url = String(urlArg);
+        const texture = new InternalTexture(this, InternalTexture.DATASOURCE_URL);
+        const url = String(urlArg);
+
+        // TODO. Find a better way.
+        // TODO. this._options.textureSize
 
         texture.url = url;
         texture.generateMipMaps = !noMipmap;
         texture.samplingMode = samplingMode;
         texture.invertY = invertY;
-        // texture.baseWidth = this._options.textureSize;
-        // texture.baseHeight = this._options.textureSize;
-        // texture.width = this._options.textureSize;
-        // texture.height = this._options.textureSize;
+
         if (format) {
             texture.format = format;
         }
 
-        texture.isReady = true;
+        let webglEngineTexture: InternalTexture;
+        const onLoadInternal = () => {
+            texture.isReady = webglEngineTexture.isReady;
+
+            const width = webglEngineTexture.width;
+            const height = webglEngineTexture.height;
+            texture.width = width;
+            texture.height = height;
+            texture.baseWidth = width;
+            texture.baseHeight = height;
+            texture._isRGBD = webglEngineTexture._isRGBD;
+            texture._sphericalPolynomial = webglEngineTexture._sphericalPolynomial;
+
+            let mipMaps = Scalar.Log2(Math.max(width, height));
+            mipMaps = Math.round(mipMaps);
+
+            const textureExtent = {
+                width,
+                height,
+                depth: 1
+            };
+            const textureDescriptor: GPUTextureDescriptor = {
+                dimension: WebGPUConstants.GPUTextureDimension_2d,
+                format: WebGPUConstants.GPUTextureFormat_rgba8unorm,
+                arrayLayerCount: 1,
+                mipLevelCount: noMipmap ? 1 : mipMaps + 1,
+                sampleCount: 1,
+                size: textureExtent,
+                usage: WebGPUConstants.GPUTextureUsage_TRANSFER_DST | WebGPUConstants.GPUTextureUsage_SAMPLED
+            }
 
-        if (onLoad) {
-            onLoad();
+            const gpuTexture = this._device.createTexture(textureDescriptor);
+            texture._webGPUTexture = gpuTexture;
+
+            // TODO.
+            const samplerDescriptor: GPUSamplerDescriptor = {
+                magFilter: "linear",
+                minFilter: "linear",
+                mipmapFilter: "linear",
+                addressModeU: "repeat",
+                addressModeV: "repeat",
+                addressModeW: "repeat",
+            };
+            const gpuSampler = this._device.createSampler(samplerDescriptor);
+            texture._webGPUSampler = gpuSampler;
+
+            if (noMipmap) {
+                this._uploadFromWebglTexture(webglEngineTexture, gpuTexture, width, height, -1);
+            }
+            else {
+                this._uploadMipMapsFromWebglTexture(mipMaps, webglEngineTexture, gpuTexture, width, height, -1);
+            }
+
+            texture._webGPUTextureView = gpuTexture.createDefaultView();
+
+            webglEngineTexture.dispose();
+
+            if (onLoad) {
+                onLoad();
+            }
         }
+        webglEngineTexture = this._decodeEngine.createTexture(urlArg, noMipmap, invertY, scene, samplingMode, 
+            onLoadInternal, onError, buffer, fallBack, format);
 
         this._internalTexturesCache.push(texture);
 
         return texture;
     }
 
-    public createRenderTargetTexture(size: any, options: boolean | RenderTargetCreationOptions): InternalTexture {
-        let fullOptions = new RenderTargetCreationOptions();
-
-        if (options !== undefined && typeof options === "object") {
-            fullOptions.generateMipMaps = options.generateMipMaps;
-            fullOptions.generateDepthBuffer = options.generateDepthBuffer === undefined ? true : options.generateDepthBuffer;
-            fullOptions.generateStencilBuffer = fullOptions.generateDepthBuffer && options.generateStencilBuffer;
-            fullOptions.type = options.type === undefined ? Constants.TEXTURETYPE_UNSIGNED_INT : options.type;
-            fullOptions.samplingMode = options.samplingMode === undefined ? Constants.TEXTURE_TRILINEAR_SAMPLINGMODE : options.samplingMode;
-        } else {
-            fullOptions.generateMipMaps = <boolean>options;
-            fullOptions.generateDepthBuffer = true;
-            fullOptions.generateStencilBuffer = false;
-            fullOptions.type = Constants.TEXTURETYPE_UNSIGNED_INT;
-            fullOptions.samplingMode = Constants.TEXTURE_TRILINEAR_SAMPLINGMODE;
+    public createCubeTexture(rootUrl: string, scene: Nullable<Scene>, files: Nullable<string[]>, noMipmap?: boolean, onLoad: Nullable<(data?: any) => void> = null, onError: Nullable<(message?: string, exception?: any) => void> = null, format?: number, forcedExtension: any = null, createPolynomials: boolean = false, lodScale: number = 0, lodOffset: number = 0, fallback: Nullable<InternalTexture> = null, excludeLoaders: Array<IInternalTextureLoader> = []): InternalTexture {
+        var texture = fallback ? fallback : new InternalTexture(this, InternalTexture.DATASOURCE_CUBE);
+        texture.isCube = true;
+        texture.url = rootUrl;
+        texture.generateMipMaps = !noMipmap;
+        texture._lodGenerationScale = lodScale;
+        texture._lodGenerationOffset = lodOffset;
+    
+        if (!this._doNotHandleContextLost) {
+            texture._extension = forcedExtension;
+            texture._files = files;
         }
-        var texture = new InternalTexture(this, InternalTexture.DATASOURCE_RENDERTARGET);
+    
+        let webglEngineTexture: InternalTexture;
+        const onLoadInternal = () => {
+            texture.isReady = webglEngineTexture.isReady;
+
+            const width = webglEngineTexture.width;
+            const height = webglEngineTexture.height;
+            const depth = 1;
+            texture.width = width;
+            texture.height = height;
+            texture.baseWidth = width;
+            texture.baseHeight = height;
+            texture.depth = depth;
+            texture.baseDepth = depth;
+            texture._isRGBD = webglEngineTexture._isRGBD;
+            texture._sphericalPolynomial = webglEngineTexture._sphericalPolynomial;
+
+            let mipMaps = Scalar.Log2(width);
+            mipMaps = Math.round(mipMaps);
+
+            const textureExtent = {
+                width,
+                height,
+                depth,
+            };
+            const textureDescriptor: GPUTextureDescriptor = {
+                dimension: WebGPUConstants.GPUTextureDimension_2d,
+                format: WebGPUConstants.GPUTextureFormat_rgba8unorm,
+                arrayLayerCount: 6,
+                mipLevelCount: noMipmap ? 1 : mipMaps + 1,
+                sampleCount: 1,
+                size: textureExtent,
+                usage: WebGPUConstants.GPUTextureUsage_TRANSFER_DST | WebGPUConstants.GPUTextureUsage_SAMPLED
+            }
 
-        var width = size.width || size;
-        var height = size.height || size;
+            const gpuTexture = this._device.createTexture(textureDescriptor);
+            texture._webGPUTexture = gpuTexture;
+
+            // TODO.
+            const samplerDescriptor: GPUSamplerDescriptor = {
+                magFilter: "linear",
+                minFilter: "linear",
+                mipmapFilter: "linear",
+                addressModeU: "repeat",
+                addressModeV: "repeat",
+                addressModeW: "repeat",
+            };
+            const gpuSampler = this._device.createSampler(samplerDescriptor);
+            texture._webGPUSampler = gpuSampler;
 
-        texture._depthStencilBuffer = {};
-        texture._framebuffer = {};
-        texture.baseWidth = width;
-        texture.baseHeight = height;
-        texture.width = width;
-        texture.height = height;
-        texture.isReady = true;
-        texture.samples = 1;
-        texture.generateMipMaps = fullOptions.generateMipMaps ? true : false;
-        texture.samplingMode = fullOptions.samplingMode;
-        texture.type = fullOptions.type;
-        texture._generateDepthBuffer = fullOptions.generateDepthBuffer;
-        texture._generateStencilBuffer = fullOptions.generateStencilBuffer ? true : false;
+            const faces = [0, 1, 2, 3, 4, 5];
+            for (let face of faces) {
+                if (noMipmap) {
+                    this._uploadFromWebglTexture(webglEngineTexture, gpuTexture, width, height, face);
+                }
+                else {
+                    this._uploadMipMapsFromWebglTexture(mipMaps, webglEngineTexture, gpuTexture, width, height, face);
+                }
+            }
+            texture._webGPUTextureView = gpuTexture.createView({
+                arrayLayerCount: 6,
+                dimension: "cube",
+                format: "rgba8unorm",
+                mipLevelCount: noMipmap ? 1 : mipMaps + 1,
+                baseArrayLayer: 0,
+                baseMipLevel: 0
+            });
+            webglEngineTexture.dispose();
+        }
+        webglEngineTexture = this._decodeEngine.createCubeTexture(rootUrl, scene, files, noMipmap, onLoadInternal, onError, format, forcedExtension, createPolynomials, lodScale, lodOffset, fallback, excludeLoaders);
 
         this._internalTexturesCache.push(texture);
-
+    
         return texture;
-    }
+    };
 
     public updateTextureSamplingMode(samplingMode: number, texture: InternalTexture): void {
         texture.samplingMode = samplingMode;
     }
 
     public updateDynamicTexture(texture: Nullable<InternalTexture>, canvas: HTMLCanvasElement, invertY: boolean, premulAlpha: boolean = false, format?: number): void {
-
+        // TODO.
+        throw "Unimplemented updateDynamicTexture on WebGPU so far";
     }
 
-    public bindSamplers(effect: Effect): void { }
-
-    /** @hidden */
-    public _getUnpackAlignement(): number {
-        return 1;
+    public setTexture(channel: number, uniform: Nullable<WebGLUniformLocation>, texture: Nullable<BaseTexture>, name: string): void {
+        if (this._currentEffect) {
+            const pipeline = this._currentEffect._pipelineContext as WebGPUPipelineContext;
+            if (!texture) {
+                pipeline.samplers[name] = null;
+            }
+            else if (pipeline.samplers[name]) {
+                pipeline.samplers[name]!.texture = texture!.getInternalTexture()!;
+            }
+            else {
+                pipeline.samplers[name] = {
+                    textureBinding: channel,
+                    samplerBinding: channel + 1,
+                    texture: texture!.getInternalTexture()!
+                };
+            }
+        }
     }
 
-    /** @hidden */
-    public _unpackFlipY(value: boolean) {
-    }
+    public bindSamplers(effect: Effect): void { }
 
     public _bindTextureDirectly(target: number, texture: InternalTexture): boolean {
         if (this._boundTexturesCache[this._activeChannel] !== texture) {
@@ -962,6 +1185,50 @@ export class WebGPUEngine extends Engine {
     }
 
     //------------------------------------------------------------------------------
+    //                              Render Target Textures
+    //------------------------------------------------------------------------------
+
+    public createRenderTargetTexture(size: any, options: boolean | RenderTargetCreationOptions): InternalTexture {
+        let fullOptions = new RenderTargetCreationOptions();
+
+        if (options !== undefined && typeof options === "object") {
+            fullOptions.generateMipMaps = options.generateMipMaps;
+            fullOptions.generateDepthBuffer = options.generateDepthBuffer === undefined ? true : options.generateDepthBuffer;
+            fullOptions.generateStencilBuffer = fullOptions.generateDepthBuffer && options.generateStencilBuffer;
+            fullOptions.type = options.type === undefined ? Constants.TEXTURETYPE_UNSIGNED_INT : options.type;
+            fullOptions.samplingMode = options.samplingMode === undefined ? Constants.TEXTURE_TRILINEAR_SAMPLINGMODE : options.samplingMode;
+        } else {
+            fullOptions.generateMipMaps = <boolean>options;
+            fullOptions.generateDepthBuffer = true;
+            fullOptions.generateStencilBuffer = false;
+            fullOptions.type = Constants.TEXTURETYPE_UNSIGNED_INT;
+            fullOptions.samplingMode = Constants.TEXTURE_TRILINEAR_SAMPLINGMODE;
+        }
+        var texture = new InternalTexture(this, InternalTexture.DATASOURCE_RENDERTARGET);
+
+        var width = size.width || size;
+        var height = size.height || size;
+
+        texture._depthStencilBuffer = {};
+        texture._framebuffer = {};
+        texture.baseWidth = width;
+        texture.baseHeight = height;
+        texture.width = width;
+        texture.height = height;
+        texture.isReady = true;
+        texture.samples = 1;
+        texture.generateMipMaps = fullOptions.generateMipMaps ? true : false;
+        texture.samplingMode = fullOptions.samplingMode;
+        texture.type = fullOptions.type;
+        texture._generateDepthBuffer = fullOptions.generateDepthBuffer;
+        texture._generateStencilBuffer = fullOptions.generateStencilBuffer ? true : false;
+
+        this._internalTexturesCache.push(texture);
+
+        return texture;
+    }
+
+    //------------------------------------------------------------------------------
     //                              Render Commands
     //------------------------------------------------------------------------------
 
@@ -1287,10 +1554,11 @@ export class WebGPUEngine extends Engine {
                     continue;
                 }
 
-                vertexBuffer.type
-
                 const positionAttributeDescriptor: GPUVertexAttributeDescriptor = {
-                    shaderLocation: location,
+                    attributeIndex: location,
+
+                    // After Migration to Canary
+                    // shaderLocation: location,
                     offset: vertexBuffer.byteOffset,
                     format: this._getVertexInputDescriptorFormat(vertexBuffer.getKind(), vertexBuffer.type, vertexBuffer.normalized),
                 };
@@ -1329,10 +1597,10 @@ export class WebGPUEngine extends Engine {
         bindings = [];
 
         // Group 1: Camera
-        if (this._currentEffect!._uniformBuffersNames["Camera"] > -1) {
+        if (this._currentEffect!._uniformBuffersNames["Scene"] > -1) {
             const groupLayoutBinding: GPUBindGroupLayoutBinding = {
                 binding: 0,
-                visibility: WebGPUConstants.GPUShaderStageBit_VERTEX,
+                visibility: WebGPUConstants.GPUShaderStageBit_VERTEX | WebGPUConstants.GPUShaderStageBit_FRAGMENT,
                 type: WebGPUConstants.GPUBindingType_uniformBuffer,
             };
             bindings.push(groupLayoutBinding);
@@ -1346,6 +1614,20 @@ export class WebGPUEngine extends Engine {
         bindings = [];
 
         // Group 3: Materials
+        if (this._currentEffect!._uniformBuffersNames["Material"] > -1) {
+            const groupLayoutBinding: GPUBindGroupLayoutBinding = {
+                binding: 0,
+                visibility: WebGPUConstants.GPUShaderStageBit_VERTEX | WebGPUConstants.GPUShaderStageBit_FRAGMENT,
+                type: WebGPUConstants.GPUBindingType_uniformBuffer,
+            };
+            bindings.push(groupLayoutBinding);
+        }
+        if (bindings.length > 0) {
+            const uniformsBindGroupLayout = this._device.createBindGroupLayout({
+                bindings,
+            });
+            bindGroupLayouts[1] = uniformsBindGroupLayout;
+        }
         bindings = [];
 
         // Group 4: Mesh
@@ -1357,11 +1639,30 @@ export class WebGPUEngine extends Engine {
             };
             bindings.push(groupLayoutBinding);
         }
+
+        // TODO. Should be on group 2 at the end so as we only have one mesh :-)
+        const samplers = this._currentEffect!._samplerList;
+        const context = this._currentEffect!._pipelineContext as WebGPUPipelineContext;
+        for (let samplerName of samplers) {
+            const bindingInfo = context.samplers[samplerName];
+            if (bindingInfo) {
+                bindings.push({
+                    binding: bindingInfo.textureBinding,
+                    visibility: WebGPUConstants.GPUShaderStageBit_FRAGMENT,
+                    type: "sampled-texture"
+                }, {
+                    binding: bindingInfo.samplerBinding,
+                    visibility: WebGPUConstants.GPUShaderStageBit_FRAGMENT,
+                    type: "sampler"
+                });
+            }
+        }
+
         if (bindings.length > 0) {
             const uniformsBindGroupLayout = this._device.createBindGroupLayout({
                 bindings,
             });
-            bindGroupLayouts[1] = uniformsBindGroupLayout;
+            bindGroupLayouts[2] = uniformsBindGroupLayout;
         }
 
         (this._currentEffect!._pipelineContext as WebGPUPipelineContext).bindGroupLayouts = bindGroupLayouts;
@@ -1441,8 +1742,8 @@ export class WebGPUEngine extends Engine {
     private _setRenderBindGroups(): void {
         const bindGroupLayouts = (this._currentEffect!._pipelineContext as WebGPUPipelineContext).bindGroupLayouts;
 
-        if (this._currentEffect!._uniformBuffersNames["Camera"] > -1) {
-            const dataBuffer = this._uniformsBuffers["Camera"];
+        if (this._currentEffect!._uniformBuffersNames["Scene"] > -1) {
+            const dataBuffer = this._uniformsBuffers["Scene"];
             const webgpuBuffer = dataBuffer.underlyingResource as GPUBuffer;
             // TODO. GC. and cache.
             const uniformBindGroup = this._device.createBindGroup({
@@ -1460,12 +1761,12 @@ export class WebGPUEngine extends Engine {
             this._currentRenderPass!.setBindGroup(0, uniformBindGroup);
         }
 
-        if (this._currentEffect!._uniformBuffersNames["Mesh"]) {
-            const dataBuffer = this._uniformsBuffers["Mesh"];
+        if (this._currentEffect!._uniformBuffersNames["Material"] > -1) {
+            const dataBuffer = this._uniformsBuffers["Material"];
             const webgpuBuffer = dataBuffer.underlyingResource as GPUBuffer;
             // TODO. GC. and cache.
             const uniformBindGroup = this._device.createBindGroup({
-                layout: bindGroupLayouts[1],
+                layout: bindGroupLayouts[0],
                 bindings: [{
                     binding: 0,
                     resource: {
@@ -1478,6 +1779,43 @@ export class WebGPUEngine extends Engine {
 
             this._currentRenderPass!.setBindGroup(1, uniformBindGroup);
         }
+
+        if (this._currentEffect!._uniformBuffersNames["Mesh"]) {
+            const dataBuffer = this._uniformsBuffers["Mesh"];
+            const webgpuBuffer = dataBuffer.underlyingResource as GPUBuffer;
+            // TODO. GC. and cache.
+            const bindings: GPUBindGroupBinding[] = [{
+                binding: 0,
+                resource: {
+                    buffer: webgpuBuffer,
+                    offset: 0,
+                    size: dataBuffer.capacity,
+                },
+            }];
+
+            // TODO. Should be on group 2 at the end so as we only have one mesh :-)
+            const samplers = this._currentEffect!._samplerList;
+            const context = this._currentEffect!._pipelineContext as WebGPUPipelineContext;
+            for (let samplerName of samplers) {
+                const bindingInfo = context.samplers[samplerName];
+                if (bindingInfo) {
+                    bindings.push({
+                        binding: bindingInfo.textureBinding,
+                        //resource: sampler.defaultView,
+                        resource: bindingInfo.texture._webGPUTextureView!,
+                    }, {
+                        binding: bindingInfo.samplerBinding,
+                        resource: bindingInfo.texture._webGPUSampler!,
+                    });
+                }
+            }
+            const uniformBindGroup = this._device.createBindGroup({
+                layout: bindGroupLayouts[2],
+                bindings: bindings,
+            });
+
+            this._currentRenderPass!.setBindGroup(2, uniformBindGroup);
+        }
     }
 
     private _setRenderPipeline(fillMode: number): void {
@@ -1491,6 +1829,10 @@ export class WebGPUEngine extends Engine {
     }
 
     public drawElementsType(fillMode: number, indexStart: number, indexCount: number, instancesCount: number = 1): void {
+        if (this._internalTexturesCache.length === 0 ||
+            !this._internalTexturesCache[0]._webGPUSampler ||
+            !this._internalTexturesCache[0]._webGPUTexture)
+            return;
         this._setRenderPipeline(fillMode);
 
         this._currentRenderPass!.drawIndexed(indexCount, instancesCount, indexStart, 0, 0);
@@ -1498,6 +1840,10 @@ export class WebGPUEngine extends Engine {
 
     public drawArraysType(fillMode: number, verticesStart: number, verticesCount: number, instancesCount: number = 1): void {
         this._currentIndexBuffer = null;
+        if (this._internalTexturesCache.length === 0 ||
+            !this._internalTexturesCache[0]._webGPUSampler ||
+            !this._internalTexturesCache[0]._webGPUTexture)
+            return;
 
         this._setRenderPipeline(fillMode);
 
@@ -1508,6 +1854,18 @@ export class WebGPUEngine extends Engine {
     //                              Misc
     //------------------------------------------------------------------------------
 
+    /**
+     * Dispose and release all associated resources
+     */
+    public dispose(): void {
+        this._decodeEngine.dispose();
+        super.dispose();
+    }
+
+    //------------------------------------------------------------------------------
+    //                              Misc
+    //------------------------------------------------------------------------------
+
     public getRenderWidth(useScreen = false): number {
         if (!useScreen && this._currentRenderTarget) {
             return this._currentRenderTarget.width;
@@ -1540,6 +1898,11 @@ export class WebGPUEngine extends Engine {
     //------------------------------------------------------------------------------
     //                              Unused WebGPU
     //------------------------------------------------------------------------------
+    public _getUnpackAlignement(): number {
+        return 1;
+    }
+
+    public _unpackFlipY(value: boolean) { }
 
     public bindUniformBlock(pipelineContext: IPipelineContext, blockName: string, index: number): void {
     }

+ 6 - 5
src/LibDeclarations/webgpu.d.ts

@@ -441,9 +441,9 @@ interface GPUSamplerDescriptor {
   maxAnisotropy?: number;
   minFilter?: GPUFilterMode;
   mipmapFilter?: GPUFilterMode;
-  rAddressMode?: GPUAddressMode;
-  sAddressMode?: GPUAddressMode;
-  tAddressMode?: GPUAddressMode;
+  addressModeU?: GPUAddressMode;
+  addressModeV?: GPUAddressMode;
+  addressModeW?: GPUAddressMode;
 }
 
 interface GPUShaderModuleDescriptor {
@@ -495,9 +495,10 @@ interface GPUTextureViewDescriptor {
 
 interface GPUVertexAttributeDescriptor {
   format?: GPUVertexFormat;
-  // inputSlot?: number;
   offset?: number;
-  shaderLocation?: number;
+  attributeIndex?: number;
+  // After Migration to Canary
+  // shaderLocation?: number;
 }
 
 interface GPUVertexInputDescriptor {

+ 55 - 39
src/Materials/PBR/pbrBaseMaterial.ts

@@ -1185,7 +1185,7 @@ export abstract class PBRBaseMaterial extends PushMaterial {
             "reflectionSampler", "reflectionSamplerLow", "reflectionSamplerHigh",
             "microSurfaceSampler", "environmentBrdfSampler", "boneSampler"];
 
-        var uniformBuffers = ["Material", "Scene"];
+        var uniformBuffers = ["Material", "Scene", "Mesh"];
 
         PBRSubSurfaceConfiguration.AddUniforms(uniforms);
         PBRSubSurfaceConfiguration.AddSamplers(samplers);
@@ -1423,7 +1423,6 @@ export abstract class PBRBaseMaterial extends PushMaterial {
 
                 if (this._environmentBRDFTexture && MaterialFlags.ReflectionTextureEnabled) {
                     defines.ENVIRONMENTBRDF = true;
-                    // Not actual true RGBD, only the B chanel is encoded as RGBD for sheen.
                     defines.ENVIRONMENTBRDF_RGBD = this._environmentBRDFTexture.isRGBD;
                 } else {
                     defines.ENVIRONMENTBRDF = false;
@@ -1561,7 +1560,9 @@ export abstract class PBRBaseMaterial extends PushMaterial {
         ubo.addUniform("pointSize", 1);
         ubo.addUniform("vReflectivityColor", 4);
         ubo.addUniform("vEmissiveColor", 3);
-        ubo.addUniform("visibility", 1);
+        ubo.addUniform("vEyePosition", 4);
+        ubo.addUniform("vAmbientColor", 3);
+
         ubo.addUniform("vDebugMode", 2);
 
         PBRClearCoatConfiguration.PrepareUniformBuffer(ubo);
@@ -1569,6 +1570,26 @@ export abstract class PBRBaseMaterial extends PushMaterial {
         PBRSheenConfiguration.PrepareUniformBuffer(ubo);
         PBRSubSurfaceConfiguration.PrepareUniformBuffer(ubo);
 
+        ubo.addUniform("vSphericalL00", 3);
+        ubo.addUniform("vSphericalL1_1", 3);
+        ubo.addUniform("vSphericalL10", 3);
+        ubo.addUniform("vSphericalL11", 3);
+        ubo.addUniform("vSphericalL2_2", 3);
+        ubo.addUniform("vSphericalL2_1", 3);
+        ubo.addUniform("vSphericalL20", 3);
+        ubo.addUniform("vSphericalL21", 3);
+        ubo.addUniform("vSphericalL22", 3);
+
+        ubo.addUniform("vSphericalX", 3);
+        ubo.addUniform("vSphericalY", 3);
+        ubo.addUniform("vSphericalZ", 3);
+        ubo.addUniform("vSphericalXX_ZZ", 3);
+        ubo.addUniform("vSphericalYY_ZZ", 3);
+        ubo.addUniform("vSphericalZZ", 3);
+        ubo.addUniform("vSphericalXY", 3);
+        ubo.addUniform("vSphericalYZ", 3);
+        ubo.addUniform("vSphericalZX", 3);
+
         ubo.create();
     }
 
@@ -1618,9 +1639,7 @@ export abstract class PBRBaseMaterial extends PushMaterial {
         this._activeEffect = effect;
 
         // Matrices
-        if (!defines.INSTANCES) {
-            this.bindOnlyWorldMatrix(world);
-        }
+        mesh.getMeshUniformBuffer().bindToEffect(effect, "Mesh");
 
         // Normal Matrix
         if (defines.OBJECTSPACE_NORMALMAP) {
@@ -1676,30 +1695,30 @@ export abstract class PBRBaseMaterial extends PushMaterial {
                         if (defines.USESPHERICALFROMREFLECTIONMAP && polynomials) {
                             if (defines.SPHERICAL_HARMONICS) {
                                 const preScaledHarmonics = polynomials.preScaledHarmonics;
-                                this._activeEffect.setVector3("vSphericalL00", preScaledHarmonics.l00);
-                                this._activeEffect.setVector3("vSphericalL1_1", preScaledHarmonics.l1_1);
-                                this._activeEffect.setVector3("vSphericalL10", preScaledHarmonics.l10);
-                                this._activeEffect.setVector3("vSphericalL11", preScaledHarmonics.l11);
-                                this._activeEffect.setVector3("vSphericalL2_2", preScaledHarmonics.l2_2);
-                                this._activeEffect.setVector3("vSphericalL2_1", preScaledHarmonics.l2_1);
-                                this._activeEffect.setVector3("vSphericalL20", preScaledHarmonics.l20);
-                                this._activeEffect.setVector3("vSphericalL21", preScaledHarmonics.l21);
-                                this._activeEffect.setVector3("vSphericalL22", preScaledHarmonics.l22);
+                                ubo.updateVector3("vSphericalL00", preScaledHarmonics.l00);
+                                ubo.updateVector3("vSphericalL1_1", preScaledHarmonics.l1_1);
+                                ubo.updateVector3("vSphericalL10", preScaledHarmonics.l10);
+                                ubo.updateVector3("vSphericalL11", preScaledHarmonics.l11);
+                                ubo.updateVector3("vSphericalL2_2", preScaledHarmonics.l2_2);
+                                ubo.updateVector3("vSphericalL2_1", preScaledHarmonics.l2_1);
+                                ubo.updateVector3("vSphericalL20", preScaledHarmonics.l20);
+                                ubo.updateVector3("vSphericalL21", preScaledHarmonics.l21);
+                                ubo.updateVector3("vSphericalL22", preScaledHarmonics.l22);
                             }
                             else {
-                                this._activeEffect.setFloat3("vSphericalX", polynomials.x.x, polynomials.x.y, polynomials.x.z);
-                                this._activeEffect.setFloat3("vSphericalY", polynomials.y.x, polynomials.y.y, polynomials.y.z);
-                                this._activeEffect.setFloat3("vSphericalZ", polynomials.z.x, polynomials.z.y, polynomials.z.z);
-                                this._activeEffect.setFloat3("vSphericalXX_ZZ", polynomials.xx.x - polynomials.zz.x,
+                                ubo.updateFloat3("vSphericalX", polynomials.x.x, polynomials.x.y, polynomials.x.z);
+                                ubo.updateFloat3("vSphericalY", polynomials.y.x, polynomials.y.y, polynomials.y.z);
+                                ubo.updateFloat3("vSphericalZ", polynomials.z.x, polynomials.z.y, polynomials.z.z);
+                                ubo.updateFloat3("vSphericalXX_ZZ", polynomials.xx.x - polynomials.zz.x,
                                     polynomials.xx.y - polynomials.zz.y,
                                     polynomials.xx.z - polynomials.zz.z);
-                                this._activeEffect.setFloat3("vSphericalYY_ZZ", polynomials.yy.x - polynomials.zz.x,
+                                ubo.updateFloat3("vSphericalYY_ZZ", polynomials.yy.x - polynomials.zz.x,
                                     polynomials.yy.y - polynomials.zz.y,
                                     polynomials.yy.z - polynomials.zz.z);
-                                this._activeEffect.setFloat3("vSphericalZZ", polynomials.zz.x, polynomials.zz.y, polynomials.zz.z);
-                                this._activeEffect.setFloat3("vSphericalXY", polynomials.xy.x, polynomials.xy.y, polynomials.xy.z);
-                                this._activeEffect.setFloat3("vSphericalYZ", polynomials.yz.x, polynomials.yz.y, polynomials.yz.z);
-                                this._activeEffect.setFloat3("vSphericalZX", polynomials.zx.x, polynomials.zx.y, polynomials.zx.z);
+                                ubo.updateFloat3("vSphericalZZ", polynomials.zz.x, polynomials.zz.y, polynomials.zz.z);
+                                ubo.updateFloat3("vSphericalXY", polynomials.xy.x, polynomials.xy.y, polynomials.xy.z);
+                                ubo.updateFloat3("vSphericalYZ", polynomials.yz.x, polynomials.yz.y, polynomials.yz.z);
+                                ubo.updateFloat3("vSphericalZX", polynomials.zx.x, polynomials.zx.y, polynomials.zx.z);
                             }
                         }
 
@@ -1766,9 +1785,6 @@ export abstract class PBRBaseMaterial extends PushMaterial {
                 ubo.updateColor3("vReflectionColor", this._reflectionColor);
                 ubo.updateColor4("vAlbedoColor", this._albedoColor, this.alpha);
 
-                // Visibility
-                ubo.updateFloat("visibility", mesh.visibility);
-
                 // Misc
                 this._lightingInfos.x = this._directIntensity;
                 this._lightingInfos.y = this._emissiveIntensity;
@@ -1777,6 +1793,18 @@ export abstract class PBRBaseMaterial extends PushMaterial {
 
                 ubo.updateVector4("vLightingIntensity", this._lightingInfos);
 
+                // Colors
+                scene.ambientColor.multiplyToRef(this._ambientColor, this._globalAmbientColor);
+
+                var eyePosition = scene._forcedViewPosition ? scene._forcedViewPosition : (scene._mirroredCameraPosition ? scene._mirroredCameraPosition : (<Camera>scene.activeCamera).globalPosition);
+                var invertNormal = (scene.useRightHandedSystem === (scene._mirroredCameraPosition != null));
+                ubo.updateFloat4("vEyePosition",
+                    eyePosition.x,
+                    eyePosition.y,
+                    eyePosition.z,
+                    invertNormal ? -1 : 1);
+                ubo.updateColor3("vAmbientColor", this._globalAmbientColor);
+
                 ubo.updateFloat2("vDebugMode", this.debugLimit, this.debugFactor);
             }
 
@@ -1842,18 +1870,6 @@ export abstract class PBRBaseMaterial extends PushMaterial {
 
             // Clip plane
             MaterialHelper.BindClipPlane(this._activeEffect, scene);
-
-            // Colors
-            scene.ambientColor.multiplyToRef(this._ambientColor, this._globalAmbientColor);
-
-            var eyePosition = scene._forcedViewPosition ? scene._forcedViewPosition : (scene._mirroredCameraPosition ? scene._mirroredCameraPosition : (<Camera>scene.activeCamera).globalPosition);
-            var invertNormal = (scene.useRightHandedSystem === (scene._mirroredCameraPosition != null));
-            effect.setFloat4("vEyePosition",
-                eyePosition.x,
-                eyePosition.y,
-                eyePosition.z,
-                invertNormal ? -1 : 1);
-            effect.setColor3("vAmbientColor", this._globalAmbientColor);
         }
 
         if (mustRebind || !this.isFrozen) {

+ 9 - 0
src/Materials/Textures/internalTexture.ts

@@ -230,6 +230,13 @@ export class InternalTexture {
     /** @hidden */
     public _webGLTexture: Nullable<WebGLTexture> = null;
     /** @hidden */
+    public _webGPUTexture: Nullable<GPUTexture> = null;
+    /** @hidden */
+    public _webGPUSampler: Nullable<GPUSampler> = null;
+    /** @hidden */
+    public _webGPUTextureView: Nullable<GPUTextureView> = null;
+
+    /** @hidden */
     public _references: number = 1;
 
     private _engine: Engine;
@@ -456,6 +463,8 @@ export class InternalTexture {
         if (this._references === 0) {
             this._engine._releaseTexture(this);
             this._webGLTexture = null;
+            this._webGPUTexture = null;
+            this._webGPUSampler = null;
         }
     }
 }

+ 52 - 16
src/Materials/effect.ts

@@ -241,11 +241,12 @@ export class Effect implements IDisposable {
     public _bonesComputationForcedToCPU = false;
     /** @hidden */
     public _uniformBuffersNames: { [key: string]: number } = {};
+    /** @hidden */
+    public _samplerList: string[];
 
     private static _uniqueIdSeed = 0;
     private _engine: Engine;
     private _uniformsNames: string[];
-    private _samplerList: string[];
     private _samplers: { [key: string]: number } = {};
     private _isReady = false;
     private _compilationError = "";
@@ -621,7 +622,7 @@ export class Effect implements IDisposable {
 
         var preparedSourceCode = this._processPrecision(sourceCode);
 
-        if (this._engine.webGLVersion == 1) {
+        if (this._engine.webGLVersion == 1 && !this._engine.isWebGPU) {
             callback(preparedSourceCode);
             return;
         }
@@ -655,7 +656,12 @@ export class Effect implements IDisposable {
             result = result.replace(/gl_FragDepthEXT/g, "gl_FragDepth");
             result = result.replace(/gl_FragColor/g, "glFragColor");
             result = result.replace(/gl_FragData/g, "glFragData");
-            result = result.replace(/void\s+?main\s*\(/g, (hasDrawBuffersExtension ? "" : "out vec4 glFragColor;\n") + "void main(");
+            if (this._engine.isWebGPU) {
+                result = result.replace(/void\s+?main\s*\(/g, "layout(location = 0) out vec4 glFragColor;\nvoid main(");
+            }
+            else {
+                result = result.replace(/void\s+?main\s*\(/g, (hasDrawBuffersExtension ? "" : "out vec4 glFragColor;\n") + "void main(");
+            }
         }
 
         // Add multiview setup to top of file when defined
@@ -826,6 +832,7 @@ export class Effect implements IDisposable {
             }
 
             engine._executeWhenRenderingStateIsCompiled(this._pipelineContext, () => {
+                // TODO. Move the WebGL Part out.
                 if (engine.supportsUniformBuffers) {
                     for (var name in this._uniformBuffersNames) {
                         this.bindUniformBlock(name, this._uniformBuffersNames[name]);
@@ -837,23 +844,52 @@ export class Effect implements IDisposable {
                     this._uniforms[this._uniformsNames[index]] = uniform;
                 });
 
-                this._attributes = engine.getAttributes(this._pipelineContext, attributesNames);
+                if (!engine.isWebGPU) {
+                    let index: number;
+                    for (index = 0; index < this._samplerList.length; index++) {
+                        const sampler = this.getUniform(this._samplerList[index]);
 
-                var index: number;
-                for (index = 0; index < this._samplerList.length; index++) {
-                    var sampler = this.getUniform(this._samplerList[index]);
-
-                    if (sampler == null) {
-                        this._samplerList.splice(index, 1);
-                        index--;
+                        if (sampler == null) {
+                            this._samplerList.splice(index, 1);
+                            index--;
+                        }
                     }
+
+                    this._samplerList.forEach((name, index) => {
+                        this._samplers[name] = index;
+                    });
                 }
+                else {
+                    // TODO. CLEANUP THIS STUFF (FOR SEB) !!!
+                    const samplersRegex = /layout\(set\s*=\s*(\d+)\s*,\s*binding\s*=\s*(\d+).*\)\s*uniform\s*(texture\S*)\s*(\S*)\s*;/gm;
+                    const foundSamplers: { [key: string]: number } = { };
+                    let matches: RegExpExecArray | null;
+                    while (matches = samplersRegex.exec(this._fragmentSourceCode)) {
+                        // const set = matches[1];
+                        const binding = matches[2];
+                        // const type = matches[3];
+                        const name = matches[4].replace("Texture", "");
+            
+                        foundSamplers[name] = +binding;
+                    }
 
-                this._samplerList.forEach((name, index) => {
-                    this._samplers[name] = index;
-                });
+                    let index: number;
+                    for (index = 0; index < this._samplerList.length; index++) {
+                        const name = this._samplerList[index]
+                        const sampler = foundSamplers[this._samplerList[index]];
+
+                        if (sampler == null || sampler == undefined) {
+                            this._samplerList.splice(index, 1);
+                            index--;
+                        }
+                        else {
+                            this._samplers[name] = sampler;
+                        }
+                    }
+                }
 
-                engine.bindSamplers(this);
+                // Generic WebGL WebGPU part.
+                this._attributes = engine.getAttributes(this._pipelineContext, attributesNames);
 
                 this._compilationError = "";
                 this._isReady = true;
@@ -941,7 +977,7 @@ export class Effect implements IDisposable {
      * @param texture Texture to set.
      */
     public setTexture(channel: string, texture: Nullable<BaseTexture>): void {
-        this._engine.setTexture(this._samplers[channel], this._uniforms[channel], texture);
+        this._engine.setTexture(this._samplers[channel], this._uniforms[channel], texture, channel);
     }
 
     /**

+ 6 - 2
src/Meshes/abstractMesh.ts

@@ -692,9 +692,13 @@ export class AbstractMesh extends TransformNode implements IDisposable, ICullabl
         // TODO. Bones.
 
         ubo.update();
+    }
 
-        // TODO WEBGPU.
-        this.getScene().getEngine().bindUniformBufferBase(ubo.getBuffer()!, 0, "Mesh");
+    /**
+     * Gets the mesh uniform buffer.
+     */
+    public getMeshUniformBuffer(): UniformBuffer {
+        return this._uniformBuffer;
     }
 
     /**

+ 1 - 0
src/Misc/brdfTextureTools.ts

@@ -97,6 +97,7 @@ export class BRDFTextureTools {
             scene.useDelayedTextureLoading = useDelayedTextureLoading;
 
             texture.onLoadObservable.addOnce(() => {
+                texture._texture!._isRGBD = true;
                 this._ExpandDefaultBRDFTexture(texture._texture!);
             });
         }

+ 1 - 0
src/Misc/index.ts

@@ -32,3 +32,4 @@ export * from "./screenshotTools";
 export * from "./typeStore";
 export * from "./webRequest";
 export * from "./iInspectable";
+export * from "./brdfTextureTools";

+ 14 - 13
src/Shaders/ShadersInclude/bumpFragmentFunctions.fx

@@ -7,16 +7,15 @@
 		uniform mat4 normalMatrix;
 	#endif
 
-	vec3 perturbNormal(mat3 cotangentFrame, vec2 uv, sampler2D textureSampler, float scale)
+	vec3 perturbNormal(mat3 cotangentFrame, vec2 uv, vec3 textureSample, float scale)
 	{
-		vec3 map = texture2D(textureSampler, uv).xyz;
-		map = map * 2.0 - 1.0;
+		textureSample = textureSample * 2.0 - 1.0;
 
 		#ifdef NORMALXYSCALE
-			map = normalize(map * vec3(scale, scale, 1.0));
+			textureSample = normalize(textureSample * vec3(scale, scale, 1.0));
 		#endif
 
-		return normalize(cotangentFrame * map);
+		return normalize(cotangentFrame * textureSample);
 	}
 
 	// Thanks to http://www.thetenthplanet.de/archives/1180
@@ -48,18 +47,20 @@
 #endif
 
 #ifdef BUMP
-	#if BUMPDIRECTUV == 1
-		#define vBumpUV vMainUV1
-	#elif BUMPDIRECTUV == 2
-		#define vBumpUV vMainUV2
-	#else
-		varying vec2 vBumpUV;
+	#ifndef PBR
+		#if BUMPDIRECTUV == 1
+			#define vBumpUV vMainUV1
+		#elif BUMPDIRECTUV == 2
+			#define vBumpUV vMainUV2
+		#else
+			varying vec2 vBumpUV;
+		#endif
+		uniform sampler2D bumpSampler;
 	#endif
-	uniform sampler2D bumpSampler;
 
 	vec3 perturbNormal(mat3 cotangentFrame, vec2 uv)
 	{
-		return perturbNormal(cotangentFrame, uv, bumpSampler, vBumpInfos.y);
+		return perturbNormal(cotangentFrame, uv, texture2D(bumpSampler, uv).xyz, vBumpInfos.y);
 	}
 
 	// Thanks to http://www.thetenthplanet.de/archives/1180

+ 0 - 20
src/Shaders/ShadersInclude/harmonicsFunctions.fx

@@ -1,15 +1,5 @@
 #ifdef USESPHERICALFROMREFLECTIONMAP
     #ifdef SPHERICAL_HARMONICS
-        uniform vec3 vSphericalL00;
-        uniform vec3 vSphericalL1_1;
-        uniform vec3 vSphericalL10;
-        uniform vec3 vSphericalL11;
-        uniform vec3 vSphericalL2_2;
-        uniform vec3 vSphericalL2_1;
-        uniform vec3 vSphericalL20;
-        uniform vec3 vSphericalL21;
-        uniform vec3 vSphericalL22;
-
         // Please note the the coefficient have been prescaled.
         //
         // This uses the theory from both Sloan and Ramamoothi:
@@ -31,16 +21,6 @@
                 + vSphericalL22 * (normal.x * normal.x - (normal.y * normal.y));
         }
     #else
-        uniform vec3 vSphericalX;
-        uniform vec3 vSphericalY;
-        uniform vec3 vSphericalZ;
-        uniform vec3 vSphericalXX_ZZ;
-        uniform vec3 vSphericalYY_ZZ;
-        uniform vec3 vSphericalZZ;
-        uniform vec3 vSphericalXY;
-        uniform vec3 vSphericalYZ;
-        uniform vec3 vSphericalZX;
-
         // By Matthew Jones.
         vec3 computeEnvironmentIrradiance(vec3 normal) {
             // Fast method for evaluating a fixed spherical harmonics function on the sphere (e.g. irradiance or radiance).

+ 2 - 2
src/Shaders/ShadersInclude/pbrBRDFFunctions.fx

@@ -15,12 +15,12 @@
 #endif
 
 #ifdef ENVIRONMENTBRDF
-    vec3 getBRDFLookup(float NdotV, float perceptualRoughness, sampler2D brdfSampler) {
+    vec3 getBRDFLookup(float NdotV, float perceptualRoughness) {
         // Indexed on cos(theta) and roughness
         vec2 UV = vec2(NdotV, perceptualRoughness);
         
         // We can find the scale and offset to apply to the specular value.
-        vec4 brdfLookup = texture2D(brdfSampler, UV);
+        vec4 brdfLookup = texture2D(environmentBrdfSampler, UV);
 
         #ifdef ENVIRONMENTBRDF_RGBD
             brdfLookup.rgb = fromRGBD(brdfLookup.rgba);

+ 28 - 1
src/Shaders/ShadersInclude/pbrFragmentDeclaration.fx

@@ -9,6 +9,9 @@ uniform vec3 vEmissiveColor;
 
 uniform float visibility;
 
+uniform vec4 vEyePosition;
+uniform vec3 vAmbientColor;
+
 // Samplers
 #ifdef ALBEDO
 uniform vec2 vAlbedoInfos;
@@ -128,4 +131,28 @@ uniform mat4 view;
 
 #if DEBUGMODE > 0
     uniform vec2 vDebugMode;
-#endif
+#endif
+
+#ifdef USESPHERICALFROMREFLECTIONMAP
+    #ifdef SPHERICAL_HARMONICS
+        uniform vec3 vSphericalL00;
+        uniform vec3 vSphericalL1_1;
+        uniform vec3 vSphericalL10;
+        uniform vec3 vSphericalL11;
+        uniform vec3 vSphericalL2_2;
+        uniform vec3 vSphericalL2_1;
+        uniform vec3 vSphericalL20;
+        uniform vec3 vSphericalL21;
+        uniform vec3 vSphericalL22;
+    #else
+        uniform vec3 vSphericalX;
+        uniform vec3 vSphericalY;
+        uniform vec3 vSphericalZ;
+        uniform vec3 vSphericalXX_ZZ;
+        uniform vec3 vSphericalYY_ZZ;
+        uniform vec3 vSphericalZZ;
+        uniform vec3 vSphericalXY;
+        uniform vec3 vSphericalYZ;
+        uniform vec3 vSphericalZX;
+    #endif
+#endif

+ 48 - 19
src/Shaders/ShadersInclude/pbrFragmentExtraDeclaration.fx

@@ -1,29 +1,58 @@
-uniform vec4 vEyePosition;
-uniform vec3 vAmbientColor;
-uniform vec4 vCameraInfos;
-
 // Input
-varying vec3 vPositionW;
-
-#if DEBUGMODE > 0
-    varying vec4 vClipSpacePosition;
+#ifdef WEBGGPU
+    layout(location = 0) in vec3 vPositionW;
+#else
+    varying vec3 vPositionW;
 #endif
 
-#ifdef MAINUV1
-    varying vec2 vMainUV1;
-#endif 
-
-#ifdef MAINUV2 
-    varying vec2 vMainUV2;
-#endif 
-
 #ifdef NORMAL
-    varying vec3 vNormalW;
+    #ifdef WEBGGPU
+        layout(location = 1) in vec3 vNormalW;
+    #else
+        varying vec3 vNormalW;
+    #endif
+
     #if defined(USESPHERICALFROMREFLECTIONMAP) && defined(USESPHERICALINVERTEX)
-        varying vec3 vEnvironmentIrradiance;
+        #ifdef WEBGGPU
+            #ifdef WEBGGPU
+                layout(location = 2) in vec3 vEnvironmentIrradiance;
+            #else
+                varying vec3 vEnvironmentIrradiance;
+            #endif
+        #else
+            varying vec3 vEnvironmentIrradiance;
+        #endif
     #endif
 #endif
 
 #ifdef VERTEXCOLOR
-    varying vec4 vColor;
+    #ifdef WEBGGPU
+        layout(location = 3) in vec4 vColor;
+    #else
+        varying vec4 vColor;
+    #endif
+#endif
+
+#if DEBUGMODE > 0
+    #ifdef WEBGGPU
+        layout(location = 5) in vec4 vClipSpacePosition;
+    #else
+        varying vec4 vClipSpacePosition;
+    #endif
+#endif
+
+#ifdef MAINUV1
+    #ifdef WEBGGPU
+        layout(location = 6) in vec2 vMainUV1;
+    #else
+        varying vec2 vMainUV1;
+    #endif
+#endif
+
+#ifdef MAINUV2
+    #ifdef WEBGGPU
+        layout(location = 7) in vec2 vMainUV2;
+    #else
+        varying vec2 vMainUV2;
+    #endif
 #endif

+ 123 - 61
src/Shaders/ShadersInclude/pbrFragmentSamplersDeclaration.fx

@@ -1,3 +1,58 @@
+#ifdef ENVIRONMENTBRDF
+    #ifdef WEBGGPU
+        layout(set = 2, binding = 1) uniform texture2D environmentBrdfSamplerTexture;
+        layout(set = 2, binding = 2) uniform sampler environmentBrdfSamplerSampler;
+        #define environmentBrdfSampler sampler2D(environmentBrdfSamplerTexture, environmentBrdfSamplerSampler)
+    #else
+        uniform sampler2D environmentBrdfSampler;
+    #endif
+#endif
+
+// Reflection
+#ifdef REFLECTION
+    #ifdef REFLECTIONMAP_3D
+        #define sampleReflection(s, c) textureCube(s, c)
+
+        #ifdef WEBGGPU
+            layout(set = 2, binding = 3) uniform textureCube reflectionSamplerTexture;
+            layout(set = 2, binding = 4) uniform sampler reflectionSamplerSampler;
+            #define reflectionSampler samplerCube(reflectionSamplerTexture, reflectionSamplerSampler)
+        #else
+            uniform samplerCube reflectionSampler;
+        #endif
+
+        #ifdef LODBASEDMICROSFURACE
+            #define sampleReflectionLod(s, c, l) textureCubeLodEXT(s, c, l)
+        #else
+            uniform samplerCube reflectionSamplerLow;
+            uniform samplerCube reflectionSamplerHigh;
+        #endif
+    #else
+        #define sampleReflection(s, c) texture2D(s, c)
+
+        uniform sampler2D reflectionSampler;
+
+        #ifdef LODBASEDMICROSFURACE
+            #define sampleReflectionLod(s, c, l) texture2DLodEXT(s, c, l)
+        #else
+            uniform samplerCube reflectionSamplerLow;
+            uniform samplerCube reflectionSamplerHigh;
+        #endif
+    #endif
+
+    #ifdef REFLECTIONMAP_SKYBOX
+        #ifdef WEBGGPU
+            layout(location = 4) in vec3 vPositionUVW;
+        #else
+            varying vec3 vPositionUVW;
+        #endif
+    #else
+        #if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)
+            varying vec3 vDirectionW;
+        #endif
+    #endif
+#endif
+
 #ifdef ALBEDO
     #if ALBEDODIRECTUV == 1
         #define vAlbedoUV vMainUV1
@@ -6,7 +61,32 @@
     #else
         varying vec2 vAlbedoUV;
     #endif
-    uniform sampler2D albedoSampler;
+
+    #ifdef WEBGGPU
+        layout(set = 2, binding = 5) uniform texture2D albedoSamplerTexture;
+        layout(set = 2, binding = 6) uniform sampler albedoSamplerSampler;
+        #define albedoSampler sampler2D(albedoSamplerTexture, albedoSamplerSampler)
+    #else
+        uniform sampler2D albedoSampler;
+    #endif
+#endif
+
+#ifdef REFLECTIVITY
+    #if REFLECTIVITYDIRECTUV == 1
+        #define vReflectivityUV vMainUV1
+    #elif REFLECTIVITYDIRECTUV == 2
+        #define vReflectivityUV vMainUV2
+    #else
+        varying vec2 vReflectivityUV;
+    #endif
+
+    #ifdef WEBGGPU
+        layout(set = 2, binding = 7) uniform texture2D reflectivitySamplerTexture;
+        layout(set = 2, binding = 8) uniform sampler reflectivitySamplerSampler;
+        #define reflectivitySampler sampler2D(reflectivitySamplerTexture, reflectivitySamplerSampler)
+    #else
+        uniform sampler2D reflectivitySampler;
+    #endif
 #endif
 
 #ifdef AMBIENT
@@ -17,18 +97,14 @@
     #else
         varying vec2 vAmbientUV;
     #endif
-    uniform sampler2D ambientSampler;
-#endif
 
-#ifdef OPACITY
-    #if OPACITYDIRECTUV == 1
-        #define vOpacityUV vMainUV1
-    #elif OPACITYDIRECTUV == 2
-        #define vOpacityUV vMainUV2
+    #ifdef WEBGGPU
+        layout(set = 2, binding = 9) uniform texture2D ambientSamplerTexture;
+        layout(set = 2, binding = 10) uniform sampler ambientSamplerSampler;
+        #define ambientSampler sampler2D(ambientSamplerTexture, ambientSamplerSampler)
     #else
-        varying vec2 vOpacityUV;
+        uniform sampler2D ambientSampler;
     #endif
-    uniform sampler2D opacitySampler;
 #endif
 
 #ifdef EMISSIVE
@@ -39,7 +115,43 @@
     #else
         varying vec2 vEmissiveUV;
     #endif
-    uniform sampler2D emissiveSampler;
+
+    #ifdef WEBGGPU
+        layout(set = 2, binding = 11) uniform texture2D emissiveSamplerTexture;
+        layout(set = 2, binding = 12) uniform sampler emissiveSamplerSampler;
+        #define emissiveSampler sampler2D(emissiveSamplerTexture, emissiveSamplerSampler)
+    #else
+        uniform sampler2D emissiveSampler;
+    #endif
+#endif
+
+#ifdef BUMP
+    #if BUMPDIRECTUV == 1
+        #define vBumpUV vMainUV1
+    #elif BUMPDIRECTUV == 2
+        #define vBumpUV vMainUV2
+    #else
+        varying vec2 vBumpUV;
+    #endif
+
+    #ifdef WEBGGPU
+        layout(set = 2, binding = 13) uniform texture2D bumpSamplerTexture;
+        layout(set = 2, binding = 14) uniform sampler bumpSamplerSampler;
+        #define bumpSampler sampler2D(bumpSamplerTexture, bumpSamplerSampler)
+    #else
+        uniform sampler2D bumpSampler;
+    #endif
+#endif
+
+#ifdef OPACITY
+    #if OPACITYDIRECTUV == 1
+        #define vOpacityUV vMainUV1
+    #elif OPACITYDIRECTUV == 2
+        #define vOpacityUV vMainUV2
+    #else
+        varying vec2 vOpacityUV;
+    #endif
+    uniform sampler2D opacitySampler;
 #endif
 
 #ifdef LIGHTMAP
@@ -53,17 +165,6 @@
     uniform sampler2D lightmapSampler;
 #endif
 
-#ifdef REFLECTIVITY
-    #if REFLECTIVITYDIRECTUV == 1
-        #define vReflectivityUV vMainUV1
-    #elif REFLECTIVITYDIRECTUV == 2
-        #define vReflectivityUV vMainUV2
-    #else
-        varying vec2 vReflectivityUV;
-    #endif
-    uniform sampler2D reflectivitySampler;
-#endif
-
 #ifdef MICROSURFACEMAP
     #if MICROSURFACEMAPDIRECTUV == 1
         #define vMicroSurfaceSamplerUV vMainUV1
@@ -136,45 +237,6 @@
     #endif
 #endif
 
-// Reflection
-#ifdef REFLECTION
-    #ifdef REFLECTIONMAP_3D
-        #define sampleReflection(s, c) textureCube(s, c)
-
-        uniform samplerCube reflectionSampler;
-        
-        #ifdef LODBASEDMICROSFURACE
-            #define sampleReflectionLod(s, c, l) textureCubeLodEXT(s, c, l)
-        #else
-            uniform samplerCube reflectionSamplerLow;
-            uniform samplerCube reflectionSamplerHigh;
-        #endif
-    #else
-        #define sampleReflection(s, c) texture2D(s, c)
-
-        uniform sampler2D reflectionSampler;
-
-        #ifdef LODBASEDMICROSFURACE
-            #define sampleReflectionLod(s, c, l) texture2DLodEXT(s, c, l)
-        #else
-            uniform samplerCube reflectionSamplerLow;
-            uniform samplerCube reflectionSamplerHigh;
-        #endif
-    #endif
-
-    #ifdef REFLECTIONMAP_SKYBOX
-        varying vec3 vPositionUVW;
-    #else
-        #if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)
-            varying vec3 vDirectionW;
-        #endif
-    #endif
-#endif
-
-#ifdef ENVIRONMENTBRDF
-    uniform sampler2D environmentBrdfSampler;
-#endif
-
 // SUBSURFACE
 #ifdef SUBSURFACE
     #ifdef SS_REFRACTION

+ 57 - 9
src/Shaders/ShadersInclude/pbrUboDeclaration.fx

@@ -1,6 +1,37 @@
 layout(std140, column_major) uniform;
 
-uniform Material
+// layout(set = 0, binding = 0) uniform Harmonics
+// {
+//     uniform vec3 vSphericalL00;
+//     uniform vec3 vSphericalL1_1;
+//     uniform vec3 vSphericalL10;
+//     uniform vec3 vSphericalL11;
+//     uniform vec3 vSphericalL2_2;
+//     uniform vec3 vSphericalL2_1;
+//     uniform vec3 vSphericalL20;
+//     uniform vec3 vSphericalL21;
+//     uniform vec3 vSphericalL22;
+
+//     uniform vec3 vSphericalX;
+//     uniform vec3 vSphericalY;
+//     uniform vec3 vSphericalZ;
+//     uniform vec3 vSphericalXX_ZZ;
+//     uniform vec3 vSphericalYY_ZZ;
+//     uniform vec3 vSphericalZZ;
+//     uniform vec3 vSphericalXY;
+//     uniform vec3 vSphericalYZ;
+//     uniform vec3 vSphericalZX;
+// }
+
+layout(set = 0, binding = 0) uniform Scene {
+    mat4 viewProjection;
+#ifdef MULTIVIEW
+	mat4 viewProjectionR;
+#endif 
+    mat4 view;
+};
+
+layout(set = 1, binding = 0) uniform Material
 {
     uniform vec2 vAlbedoInfos;
     uniform vec4 vAmbientInfos;
@@ -30,8 +61,8 @@ uniform Material
     uniform float pointSize;
     uniform vec4 vReflectivityColor;
     uniform vec3 vEmissiveColor;
-
-    uniform float visibility;
+    uniform vec4 vEyePosition;
+    uniform vec3 vAmbientColor;
 
     uniform vec2 vDebugMode;
 
@@ -64,12 +95,29 @@ uniform Material
     uniform vec3 vDiffusionDistance;
     uniform vec4 vTintColor;
     uniform vec3 vSubSurfaceIntensity;
+
+    uniform vec3 vSphericalL00;
+    uniform vec3 vSphericalL1_1;
+    uniform vec3 vSphericalL10;
+    uniform vec3 vSphericalL11;
+    uniform vec3 vSphericalL2_2;
+    uniform vec3 vSphericalL2_1;
+    uniform vec3 vSphericalL20;
+    uniform vec3 vSphericalL21;
+    uniform vec3 vSphericalL22;
+
+    uniform vec3 vSphericalX;
+    uniform vec3 vSphericalY;
+    uniform vec3 vSphericalZ;
+    uniform vec3 vSphericalXX_ZZ;
+    uniform vec3 vSphericalYY_ZZ;
+    uniform vec3 vSphericalZZ;
+    uniform vec3 vSphericalXY;
+    uniform vec3 vSphericalYZ;
+    uniform vec3 vSphericalZX;
 };
 
-uniform Scene {
-    mat4 viewProjection;
-#ifdef MULTIVIEW
-	mat4 viewProjectionR;
-#endif 
-    mat4 view;
+layout(set = 2, binding = 0) uniform Mesh {
+    mat4 world;
+    float visibility;
 };

+ 30 - 0
src/Shaders/ShadersInclude/pbrVertexDeclaration.fx

@@ -1,6 +1,8 @@
 uniform mat4 view;
 uniform mat4 viewProjection;
 
+uniform mat4 world;
+
 #ifdef ALBEDO
 uniform mat4 albedoMatrix;
 uniform vec2 vAlbedoInfos;
@@ -98,3 +100,31 @@ uniform float pointSize;
     #endif
 #endif
 
+#ifdef NORMAL
+    #if defined(USESPHERICALFROMREFLECTIONMAP) && defined(USESPHERICALINVERTEX)
+        #ifdef USESPHERICALFROMREFLECTIONMAP
+            #ifdef SPHERICAL_HARMONICS
+                uniform vec3 vSphericalL00;
+                uniform vec3 vSphericalL1_1;
+                uniform vec3 vSphericalL10;
+                uniform vec3 vSphericalL11;
+                uniform vec3 vSphericalL2_2;
+                uniform vec3 vSphericalL2_1;
+                uniform vec3 vSphericalL20;
+                uniform vec3 vSphericalL21;
+                uniform vec3 vSphericalL22;
+            #else
+                uniform vec3 vSphericalX;
+                uniform vec3 vSphericalY;
+                uniform vec3 vSphericalZ;
+                uniform vec3 vSphericalXX_ZZ;
+                uniform vec3 vSphericalYY_ZZ;
+                uniform vec3 vSphericalZZ;
+                uniform vec3 vSphericalXY;
+                uniform vec3 vSphericalYZ;
+                uniform vec3 vSphericalZX;
+            #endif
+        #endif
+    #endif
+#endif
+

+ 3 - 3
src/Shaders/pbr.fragment.fx

@@ -647,7 +647,7 @@ void main(void) {
                 clearCoatNormalW = normalize(texture2D(clearCoatBumpSampler, vClearCoatBumpUV + uvOffset).xyz  * 2.0 - 1.0);
                 clearCoatNormalW = normalize(mat3(normalMatrix) * clearCoatNormalW);
             #else
-                clearCoatNormalW = perturbNormal(TBN, vClearCoatBumpUV + uvOffset, clearCoatBumpSampler, vClearCoatBumpInfos.y);
+                clearCoatNormalW = perturbNormal(TBN, vClearCoatBumpUV + uvOffset, texture2D(clearCoatBumpSampler, uv).xyz, vClearCoatBumpInfos.y);
             #endif
         #endif
 
@@ -751,7 +751,7 @@ void main(void) {
     // _____________________________ IBL BRDF + Energy Cons ________________________________
     #if defined(ENVIRONMENTBRDF)
         // BRDF Lookup
-        vec3 environmentBrdf = getBRDFLookup(NdotV, roughness, environmentBrdfSampler);
+        vec3 environmentBrdf = getBRDFLookup(NdotV, roughness);
 
         #ifdef MS_BRDF_ENERGY_CONSERVATION
             vec3 energyConservationFactor = getEnergyConservationFactor(specularEnvironmentR0, environmentBrdf);
@@ -878,7 +878,7 @@ void main(void) {
     #ifdef CLEARCOAT
         #if defined(ENVIRONMENTBRDF) && !defined(REFLECTIONMAP_SKYBOX)
             // BRDF Lookup
-            vec3 environmentClearCoatBrdf = getBRDFLookup(clearCoatNdotV, clearCoatRoughness, environmentBrdfSampler);
+            vec3 environmentClearCoatBrdf = getBRDFLookup(clearCoatNdotV, clearCoatRoughness);
             vec3 clearCoatEnvironmentReflectance = getReflectanceFromBRDFLookup(vec3(vClearCoatRefractionParams.x), environmentClearCoatBrdf);
 
             #ifdef RADIANCEOCCLUSION

+ 107 - 41
src/Shaders/pbr.vertex.fx

@@ -5,34 +5,127 @@
 #define CUSTOM_VERTEX_BEGIN
 
 // Attributes
-attribute vec3 position;
+#ifdef WEBGGPU
+    layout(location = 0) in vec3 position;
+#else
+    attribute vec3 position;
+#endif
+
 #ifdef NORMAL
-attribute vec3 normal;
+    #ifdef WEBGGPU
+        layout(location = 1) in vec3 normal;
+    #else
+        attribute vec3 normal;
+    #endif
 #endif
+
 #ifdef TANGENT
-attribute vec4 tangent;
+    #ifdef WEBGGPU
+        layout(location = 2) in vec4 tangent;
+    #else
+        attribute vec4 tangent;
+    #endif
 #endif
+
 #ifdef UV1
-attribute vec2 uv;
+    #ifdef WEBGGPU
+        layout(location = 3) in vec2 uv;
+    #else
+        attribute vec2 uv;
+    #endif
 #endif
+
 #ifdef UV2
-attribute vec2 uv2;
-#endif
-#ifdef MAINUV1
-varying vec2 vMainUV1;
+    #ifdef WEBGGPU
+        layout(location = 4) in vec2 uv2;
+    #else
+        attribute vec2 uv2;
+    #endif
 #endif
-#ifdef MAINUV2
-varying vec2 vMainUV2; 
-#endif 
+
 #ifdef VERTEXCOLOR
-attribute vec4 color;
+    #ifdef WEBGGPU
+        layout(location = 5) in vec4 color;
+    #else
+        attribute vec4 color;
+    #endif
 #endif
 
 #include<helperFunctions>
 #include<bonesDeclaration>
 
 // Uniforms
-#include<instancesDeclaration>
+#ifdef INSTANCES
+	attribute vec4 world0;
+	attribute vec4 world1;
+	attribute vec4 world2;
+	attribute vec4 world3;
+#endif
+
+// Output
+#ifdef WEBGGPU
+    layout(location = 0) out vec3 vPositionW;
+#else
+    varying vec3 vPositionW;
+#endif
+
+#ifdef NORMAL
+    #ifdef WEBGGPU
+        layout(location = 1) out vec3 vNormalW;
+    #else
+        varying vec3 vNormalW;
+    #endif
+
+    #if defined(USESPHERICALFROMREFLECTIONMAP) && defined(USESPHERICALINVERTEX)
+        #ifdef WEBGGPU
+            layout(location = 2) out vec3 vEnvironmentIrradiance;
+        #else
+            varying vec3 vEnvironmentIrradiance;
+        #endif
+        
+        #include<harmonicsFunctions>
+    #endif
+#endif
+
+#ifdef VERTEXCOLOR
+    #ifdef WEBGGPU
+        layout(location = 3) out vec4 vColor;
+    #else
+        varying vec4 vColor;
+    #endif
+#endif
+
+#ifdef REFLECTIONMAP_SKYBOX
+    #ifdef WEBGGPU
+        layout(location = 4) out vec3 vPositionUVW;
+    #else
+        varying vec3 vPositionUVW;
+    #endif
+#endif
+
+#if DEBUGMODE > 0
+    #ifdef WEBGGPU
+        layout(location = 5) out vec4 vClipSpacePosition;
+    #else
+        varying vec4 vClipSpacePosition;
+    #endif
+#endif
+
+#ifdef MAINUV1
+    #ifdef WEBGGPU
+        layout(location = 6) out vec2 vMainUV1;
+    #else
+        varying vec2 vMainUV1;
+    #endif
+#endif
+
+#ifdef MAINUV2
+    #ifdef WEBGGPU
+        layout(location = 7) out vec2 vMainUV2;
+    #else
+        varying vec2 vMainUV2;
+    #endif
+#endif
 
 #if defined(ALBEDO) && ALBEDODIRECTUV == 0
 varying vec2 vAlbedoUV;
@@ -98,41 +191,14 @@ varying vec2 vBumpUV;
     #endif
 #endif
 
-// Output
-varying vec3 vPositionW;
-#if DEBUGMODE > 0
-    varying vec4 vClipSpacePosition;
-#endif
-#ifdef NORMAL
-    varying vec3 vNormalW;
-    #if defined(USESPHERICALFROMREFLECTIONMAP) && defined(USESPHERICALINVERTEX)
-        varying vec3 vEnvironmentIrradiance;
-        
-        #include<harmonicsFunctions>
-    #endif
-#endif
-
-#ifdef VERTEXCOLOR
-varying vec4 vColor;
-#endif
-
 #include<bumpVertexDeclaration>
 #include<clipPlaneVertexDeclaration>
 #include<fogVertexDeclaration>
 #include<__decl__lightFragment>[0..maxSimultaneousLights]
-
 #include<morphTargetsVertexGlobalDeclaration>
 #include<morphTargetsVertexDeclaration>[0..maxSimultaneousMorphTargets]
-
-#ifdef REFLECTIONMAP_SKYBOX
-varying vec3 vPositionUVW;
-#endif
-
-#if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)
-varying vec3 vDirectionW;
-#endif
-
 #include<logDepthDeclaration>
+
 #define CUSTOM_VERTEX_DEFINITIONS
 
 void main(void) {