Browse Source

Morph Targets

Sebastien Vandenberghe 6 years ago
parent
commit
2eb2841e94

+ 1 - 1
src/Engines/Processors/iShaderProcessor.ts

@@ -5,7 +5,7 @@ import { ShaderProcessingContext } from "./shaderProcessingOptions";
 export interface IShaderProcessor {
 export interface IShaderProcessor {
     attributeProcessor?: (attribute: string, processingContext: Nullable<ShaderProcessingContext>) => string;
     attributeProcessor?: (attribute: string, processingContext: Nullable<ShaderProcessingContext>) => string;
     varyingProcessor?: (varying: string, isFragment: boolean, processingContext: Nullable<ShaderProcessingContext>) => string;
     varyingProcessor?: (varying: string, isFragment: boolean, processingContext: Nullable<ShaderProcessingContext>) => string;
-    uniformProcessor?: (uniform: string, isFragment: boolean, processingContext: Nullable<ShaderProcessingContext>) => string;
+    uniformProcessor?: (uniform: string, isFragment: boolean, preProcessors: { [key: string]: string }, processingContext: Nullable<ShaderProcessingContext>) => string;
     uniformBufferProcessor?: (uniformBuffer: string, isFragment: boolean, processingContext: Nullable<ShaderProcessingContext>) => string;
     uniformBufferProcessor?: (uniformBuffer: string, isFragment: boolean, processingContext: Nullable<ShaderProcessingContext>) => string;
     endOfUniformBufferProcessor?: (closingBracketLine: string, isFragment: boolean, processingContext: Nullable<ShaderProcessingContext>) => string;
     endOfUniformBufferProcessor?: (closingBracketLine: string, isFragment: boolean, processingContext: Nullable<ShaderProcessingContext>) => string;
     lineProcessor?: (line: string, isFragment: boolean, processingContext: Nullable<ShaderProcessingContext>) => string;
     lineProcessor?: (line: string, isFragment: boolean, processingContext: Nullable<ShaderProcessingContext>) => string;

+ 1 - 1
src/Engines/Processors/shaderCodeNode.ts

@@ -27,7 +27,7 @@ export class ShaderCodeNode {
 
 
                     if (regex.test(this.line)) { // uniform
                     if (regex.test(this.line)) { // uniform
                         if (processor.uniformProcessor) {
                         if (processor.uniformProcessor) {
-                            value = processor.uniformProcessor(this.line, options.isFragment, options.processingContext);
+                            value = processor.uniformProcessor(this.line, options.isFragment, preprocessors, options.processingContext);
                         }
                         }
                     } else { // Uniform buffer
                     } else { // Uniform buffer
                         if (processor.uniformBufferProcessor) {
                         if (processor.uniformBufferProcessor) {

+ 10 - 6
src/Engines/WebGPU/webgpuPipelineContext.ts

@@ -50,7 +50,7 @@ export class WebGPUPipelineContext implements IPipelineContext {
     public orderedAttributes: string[];
     public orderedAttributes: string[];
     public orderedUBOsAndSamplers: { name: string, isSampler: boolean }[][];
     public orderedUBOsAndSamplers: { name: string, isSampler: boolean }[][];
 
 
-    public leftOverUniforms: { name: string, type: string }[];
+    public leftOverUniforms: { name: string, type: string, length: number }[];
     public leftOverUniformsByName: { [name: string]: string };
     public leftOverUniformsByName: { [name: string]: string };
 
 
     public sources: {
     public sources: {
@@ -154,7 +154,7 @@ export class WebGPUPipelineContext implements IPipelineContext {
 
 
         for (let leftOverUniform of this.leftOverUniforms) {
         for (let leftOverUniform of this.leftOverUniforms) {
             const size = _uniformSizes[leftOverUniform.type];
             const size = _uniformSizes[leftOverUniform.type];
-            this.uniformBuffer.addUniform(leftOverUniform.name, size);
+            this.uniformBuffer.addUniform(leftOverUniform.name, size, leftOverUniform.length);
             // TODO WEBGPU. Replace with info from uniform buffer class
             // TODO WEBGPU. Replace with info from uniform buffer class
             this.leftOverUniformsByName[leftOverUniform.name] = leftOverUniform.type;
             this.leftOverUniformsByName[leftOverUniform.name] = leftOverUniform.type;
         }
         }
@@ -223,8 +223,10 @@ export class WebGPUPipelineContext implements IPipelineContext {
      * @param array array to be set.
      * @param array array to be set.
      */
      */
     public setFloatArray(uniformName: string, array: Float32Array): void {
     public setFloatArray(uniformName: string, array: Float32Array): void {
-        // TODO WEBGPU. MorphTarget.
-        throw "setFloatArray not Supported in LeftOver UBO.";
+        if (!this.uniformBuffer || !this.leftOverUniformsByName[uniformName]) {
+            return;
+        }
+        this.uniformBuffer.updateFloatArray(uniformName, array);
     }
     }
 
 
     /**
     /**
@@ -301,8 +303,10 @@ export class WebGPUPipelineContext implements IPipelineContext {
      * @param matrices matrices to be set.
      * @param matrices matrices to be set.
      */
      */
     public setMatrices(uniformName: string, matrices: Float32Array): void {
     public setMatrices(uniformName: string, matrices: Float32Array): void {
-        // TODO WEBGPU.
-        throw "setMatrices not Supported in LeftOver UBO.";
+        if (!this.uniformBuffer || !this.leftOverUniformsByName[uniformName]) {
+            return;
+        }
+        this.uniformBuffer.updateMatrices(uniformName, matrices);
     }
     }
 
 
     /**
     /**

+ 1 - 1
src/Engines/WebGPU/webgpuShaderProcessingContext.ts

@@ -18,7 +18,7 @@ export class WebGPUShaderProcessingContext implements ShaderProcessingContext {
     public availableUBOs: { [key: string]: { setIndex: number, bindingIndex: number} };
     public availableUBOs: { [key: string]: { setIndex: number, bindingIndex: number} };
     public availableSamplers: { [key: string]: { setIndex: number, bindingIndex: number} };
     public availableSamplers: { [key: string]: { setIndex: number, bindingIndex: number} };
 
 
-    public leftOverUniforms: { name: string, type: string }[];
+    public leftOverUniforms: { name: string, type: string, length: number }[];
 
 
     public orderedAttributes: string[];
     public orderedAttributes: string[];
     public orderedUBOsAndSamplers: { name: string, isSampler: boolean }[][];
     public orderedUBOsAndSamplers: { name: string, isSampler: boolean }[][];

+ 27 - 4
src/Engines/WebGPU/webgpuShaderProcessors.ts

@@ -5,6 +5,10 @@ import { WebGPUShaderProcessingContext } from './webgpuShaderProcessingContext';
 
 
 const _knownUBOs: { [key: string]: { setIndex: number, bindingIndex: number} } = {
 const _knownUBOs: { [key: string]: { setIndex: number, bindingIndex: number} } = {
     "Scene": { setIndex: 0, bindingIndex: 0 },
     "Scene": { setIndex: 0, bindingIndex: 0 },
+    "Light0": { setIndex: 0, bindingIndex: 5 },
+    "Light1": { setIndex: 0, bindingIndex: 6 },
+    "Light2": { setIndex: 0, bindingIndex: 7 },
+    "Light3": { setIndex: 0, bindingIndex: 8 },
     "Material": { setIndex: 1, bindingIndex: 0 },
     "Material": { setIndex: 1, bindingIndex: 0 },
     "Mesh": { setIndex: 1, bindingIndex: 1 },
     "Mesh": { setIndex: 1, bindingIndex: 1 },
 };
 };
@@ -70,7 +74,7 @@ export class WebGPUShaderProcessor implements IShaderProcessor {
         return attribute;
         return attribute;
     }
     }
 
 
-    public uniformProcessor(uniform: string, isFragment: boolean, processingContext: Nullable<ShaderProcessingContext>): string {
+    public uniformProcessor(uniform: string, isFragment: boolean, preProcessors: { [key: string]: string }, processingContext: Nullable<ShaderProcessingContext>): string {
         const webgpuProcessingContext = processingContext! as WebGPUShaderProcessingContext;
         const webgpuProcessingContext = processingContext! as WebGPUShaderProcessingContext;
 
 
         const uniformRegex = new RegExp(/\s*uniform\s+(\S+)\s+(\S+)\s*;/gm);
         const uniformRegex = new RegExp(/\s*uniform\s+(\S+)\s+(\S+)\s*;/gm);
@@ -78,7 +82,7 @@ export class WebGPUShaderProcessor implements IShaderProcessor {
         const match = uniformRegex.exec(uniform);
         const match = uniformRegex.exec(uniform);
         if (match != null) {
         if (match != null) {
             const uniformType = match[1];
             const uniformType = match[1];
-            const name = match[2];
+            let name = match[2];
 
 
             // TODO WEBGPU. Ensures it does not conflict with some of today's used construct for shadows.
             // TODO WEBGPU. Ensures it does not conflict with some of today's used construct for shadows.
             if (uniformType.indexOf("texture") === 0 || uniformType.indexOf("sampler") === 0) {
             if (uniformType.indexOf("texture") === 0 || uniformType.indexOf("sampler") === 0) {
@@ -105,9 +109,23 @@ export class WebGPUShaderProcessor implements IShaderProcessor {
                 webgpuProcessingContext.orderedUBOsAndSamplers[setIndex][textureBindingIndex] = { isSampler: true, name };
                 webgpuProcessingContext.orderedUBOsAndSamplers[setIndex][textureBindingIndex] = { isSampler: true, name };
             }
             }
             else {
             else {
+                // Check the size of the uniform array in case of array.
+                let length = 0;
+                const startArray = name.indexOf("[");
+                const endArray = name.indexOf("]");
+                if (startArray > 0 && endArray > 0) {
+                    const lengthInString = name.substring(startArray + 1, endArray);
+                    length = +(lengthInString);
+                    if (isNaN(length)) {
+                        length = +(preProcessors[lengthInString]);
+                    }
+                    name = name.substr(0, startArray);
+                }
+
                 webgpuProcessingContext.leftOverUniforms.push({
                 webgpuProcessingContext.leftOverUniforms.push({
                     name,
                     name,
-                    type: uniformType
+                    type: uniformType,
+                    length
                 });
                 });
                 uniform = "";
                 uniform = "";
             }
             }
@@ -218,7 +236,12 @@ export class WebGPUShaderProcessor implements IShaderProcessor {
 
 
             let ubo = `layout(set = ${availableUBO.setIndex}, binding = ${availableUBO.bindingIndex}) uniform ${name} {\n    `;
             let ubo = `layout(set = ${availableUBO.setIndex}, binding = ${availableUBO.bindingIndex}) uniform ${name} {\n    `;
             for (let leftOverUniform of webgpuProcessingContext.leftOverUniforms) {
             for (let leftOverUniform of webgpuProcessingContext.leftOverUniforms) {
-                ubo += `    ${leftOverUniform.type} ${leftOverUniform.name};\n`;
+                if (leftOverUniform.length > 0) {
+                    ubo += `    ${leftOverUniform.type} ${leftOverUniform.name}[${leftOverUniform.length}];\n`;
+                }
+                else {
+                    ubo += `    ${leftOverUniform.type} ${leftOverUniform.name};\n`;
+                }
             }
             }
             ubo += "};\n\n";
             ubo += "};\n\n";
 
 

+ 47 - 9
src/Engines/webgpuEngine.ts

@@ -121,7 +121,7 @@ export class WebGPUEngine extends Engine {
         availableSamplers: { [key: string]: { setIndex: number, bindingIndex: number} },
         availableSamplers: { [key: string]: { setIndex: number, bindingIndex: number} },
         orderedAttributes: string[],
         orderedAttributes: string[],
         orderedUBOsAndSamplers: { name: string, isSampler: boolean }[][],
         orderedUBOsAndSamplers: { name: string, isSampler: boolean }[][],
-        leftOverUniforms: { name: string, type: string }[],
+        leftOverUniforms: { name: string, type: string, length: number }[],
         leftOverUniformsByName: { [name: string]: string },
         leftOverUniformsByName: { [name: string]: string },
         sources: {
         sources: {
             vertex: string
             vertex: string
@@ -1906,9 +1906,50 @@ export class WebGPUEngine extends Engine {
                     case VertexBuffer.FLOAT:
                     case VertexBuffer.FLOAT:
                         return WebGPUConstants.GPUVertexFormat_float4;
                         return WebGPUConstants.GPUVertexFormat_float4;
                 }
                 }
-            default:
-                throw new Error("Invalid kind '" + kind + "'");
         }
         }
+
+        // MorphTargets
+        if (kind.indexOf("position") === 0 ||
+            kind.indexOf("normal") === 0 ||
+            kind.indexOf("tangent") === 0) {
+            switch (type) {
+                case VertexBuffer.BYTE:
+                    return normalized ? WebGPUConstants.GPUVertexFormat_char3norm : WebGPUConstants.GPUVertexFormat_char3;
+                case VertexBuffer.UNSIGNED_BYTE:
+                    return normalized ? WebGPUConstants.GPUVertexFormat_uchar3norm : WebGPUConstants.GPUVertexFormat_uchar3;
+                case VertexBuffer.SHORT:
+                    return normalized ? WebGPUConstants.GPUVertexFormat_short3norm : WebGPUConstants.GPUVertexFormat_short3;
+                case VertexBuffer.UNSIGNED_SHORT:
+                    return normalized ? WebGPUConstants.GPUVertexFormat_ushort3norm : WebGPUConstants.GPUVertexFormat_ushort3;
+                case VertexBuffer.INT:
+                    return WebGPUConstants.GPUVertexFormat_int3;
+                case VertexBuffer.UNSIGNED_INT:
+                    return WebGPUConstants.GPUVertexFormat_uint3;
+                case VertexBuffer.FLOAT:
+                    return WebGPUConstants.GPUVertexFormat_float3;
+            }
+        }
+        if (kind.indexOf("uv_") === 0) {
+            switch (type) {
+                case VertexBuffer.BYTE:
+                    return normalized ? WebGPUConstants.GPUVertexFormat_char2norm : WebGPUConstants.GPUVertexFormat_char2;
+                case VertexBuffer.UNSIGNED_BYTE:
+                    return normalized ? WebGPUConstants.GPUVertexFormat_uchar2norm : WebGPUConstants.GPUVertexFormat_uchar2;
+                case VertexBuffer.SHORT:
+                    return normalized ? WebGPUConstants.GPUVertexFormat_short2norm : WebGPUConstants.GPUVertexFormat_short2;
+                case VertexBuffer.UNSIGNED_SHORT:
+                    return normalized ? WebGPUConstants.GPUVertexFormat_ushort2norm : WebGPUConstants.GPUVertexFormat_ushort2;
+                case VertexBuffer.INT:
+                    return WebGPUConstants.GPUVertexFormat_int2;
+                case VertexBuffer.UNSIGNED_INT:
+                    return WebGPUConstants.GPUVertexFormat_uint2;
+                case VertexBuffer.FLOAT:
+                    return WebGPUConstants.GPUVertexFormat_float2;
+            }
+        }
+
+        // TODO WEBGPU. Manages Custom Attributes.
+        throw new Error("Invalid kind '" + kind + "'");
     }
     }
 
 
     private _getVertexInputDescriptor(): GPUInputStateDescriptor {
     private _getVertexInputDescriptor(): GPUInputStateDescriptor {
@@ -2295,18 +2336,15 @@ export class WebGPUEngine extends Engine {
 
 
     public _unpackFlipY(value: boolean) { }
     public _unpackFlipY(value: boolean) { }
 
 
-    /**
-     * Apply all cached states (depth, culling, stencil and alpha)
-     */
+    // TODO WEBGPU. All of this should go once engine split with baseEngine.
     public applyStates() {
     public applyStates() {
         // TODO WEBGPU. Apply States dynamically.
         // TODO WEBGPU. Apply States dynamically.
         // This is done at the pipeline creation level for the moment...
         // This is done at the pipeline creation level for the moment...
     }
     }
 
 
-    // TODO WEBGPU. All of this should go once engine split with baseEngine.
     /** @hidden */
     /** @hidden */
-    public _getSamplingParameters(samplingMode: number, generateMipMaps: boolean): { min: number; mag: number } { 
-        throw "_getSamplingParameters does not make sense in WebGPU";
+    public _getSamplingParameters(samplingMode: number, generateMipMaps: boolean): { min: number; mag: number } {
+        throw "_getSamplingParameters is not available in WebGPU";
     }
     }
 
 
     public bindUniformBlock(pipelineContext: IPipelineContext, blockName: string, index: number): void {
     public bindUniformBlock(pipelineContext: IPipelineContext, blockName: string, index: number): void {

+ 121 - 10
src/Materials/uniformBuffer.ts

@@ -23,8 +23,9 @@ export class UniformBuffer {
     private _data: number[];
     private _data: number[];
     private _bufferData: Float32Array;
     private _bufferData: Float32Array;
     private _dynamic?: boolean;
     private _dynamic?: boolean;
-    private _uniformLocations: { [key: string]: number; };
-    private _uniformSizes: { [key: string]: number; };
+    private _uniformLocations: { [key: string]: number };
+    private _uniformSizes: { [key: string]: number };
+    private _uniformArraySizes: { [key: string]: { strideSize: number, arraySize: number } };
     private _uniformLocationPointer: number;
     private _uniformLocationPointer: number;
     private _needSync: boolean;
     private _needSync: boolean;
     private _noUBO: boolean;
     private _noUBO: boolean;
@@ -77,6 +78,13 @@ export class UniformBuffer {
     public updateFloat4: (name: string, x: number, y: number, z: number, w: number, suffix?: string) => void;
     public updateFloat4: (name: string, x: number, y: number, z: number, w: number, suffix?: string) => void;
 
 
     /**
     /**
+     * Lambda to Update an array of float in a uniform buffer.
+     * This is dynamic to allow compat with webgl 1 and 2.
+     * You will need to pass the name of the uniform as well as the value.
+     */
+    public updateFloatArray: (name: string, array: Float32Array) => void;
+
+    /**
      * Lambda to Update a 4x4 Matrix in a uniform buffer.
      * Lambda to Update a 4x4 Matrix in a uniform buffer.
      * This is dynamic to allow compat with webgl 1 and 2.
      * This is dynamic to allow compat with webgl 1 and 2.
      * You will need to pass the name of the uniform as well as the value.
      * You will need to pass the name of the uniform as well as the value.
@@ -84,6 +92,13 @@ export class UniformBuffer {
     public updateMatrix: (name: string, mat: IMatrixLike) => void;
     public updateMatrix: (name: string, mat: IMatrixLike) => void;
 
 
     /**
     /**
+     * Lambda to Update an array of 4x4 Matrix in a uniform buffer.
+     * This is dynamic to allow compat with webgl 1 and 2.
+     * You will need to pass the name of the uniform as well as the value.
+     */
+    public updateMatrices:  (name: string, mat: Float32Array) => void;
+
+    /**
      * Lambda to Update vec3 of float from a Vector in a uniform buffer.
      * Lambda to Update vec3 of float from a Vector in a uniform buffer.
      * This is dynamic to allow compat with webgl 1 and 2.
      * This is dynamic to allow compat with webgl 1 and 2.
      * You will need to pass the name of the uniform as well as the value.
      * You will need to pass the name of the uniform as well as the value.
@@ -133,6 +148,7 @@ export class UniformBuffer {
 
 
         this._uniformLocations = {};
         this._uniformLocations = {};
         this._uniformSizes = {};
         this._uniformSizes = {};
+        this._uniformArraySizes = {};
         this._uniformLocationPointer = 0;
         this._uniformLocationPointer = 0;
         this._needSync = false;
         this._needSync = false;
 
 
@@ -143,7 +159,9 @@ export class UniformBuffer {
             this.updateFloat2 = this._updateFloat2ForEffect;
             this.updateFloat2 = this._updateFloat2ForEffect;
             this.updateFloat3 = this._updateFloat3ForEffect;
             this.updateFloat3 = this._updateFloat3ForEffect;
             this.updateFloat4 = this._updateFloat4ForEffect;
             this.updateFloat4 = this._updateFloat4ForEffect;
+            this.updateFloatArray = this._updateFloatArrayForEffect;
             this.updateMatrix = this._updateMatrixForEffect;
             this.updateMatrix = this._updateMatrixForEffect;
+            this.updateMatrices = this._updateMatricesForEffect;
             this.updateVector3 = this._updateVector3ForEffect;
             this.updateVector3 = this._updateVector3ForEffect;
             this.updateVector4 = this._updateVector4ForEffect;
             this.updateVector4 = this._updateVector4ForEffect;
             this.updateColor3 = this._updateColor3ForEffect;
             this.updateColor3 = this._updateColor3ForEffect;
@@ -157,7 +175,9 @@ export class UniformBuffer {
             this.updateFloat2 = this._updateFloat2ForUniform;
             this.updateFloat2 = this._updateFloat2ForUniform;
             this.updateFloat3 = this._updateFloat3ForUniform;
             this.updateFloat3 = this._updateFloat3ForUniform;
             this.updateFloat4 = this._updateFloat4ForUniform;
             this.updateFloat4 = this._updateFloat4ForUniform;
+            this.updateFloatArray = this._updateFloatArrayForUniform;
             this.updateMatrix = this._updateMatrixForUniform;
             this.updateMatrix = this._updateMatrixForUniform;
+            this.updateMatrices = this._updateMatricesForUniform;
             this.updateVector3 = this._updateVector3ForUniform;
             this.updateVector3 = this._updateVector3ForUniform;
             this.updateVector4 = this._updateVector4ForUniform;
             this.updateVector4 = this._updateVector4ForUniform;
             this.updateColor3 = this._updateColor3ForUniform;
             this.updateColor3 = this._updateColor3ForUniform;
@@ -242,8 +262,9 @@ export class UniformBuffer {
      * for the layout to be correct !
      * for the layout to be correct !
      * @param name Name of the uniform, as used in the uniform block in the shader.
      * @param name Name of the uniform, as used in the uniform block in the shader.
      * @param size Data size, or data directly.
      * @param size Data size, or data directly.
+     * @param arraySize The number of elements in the array, 0 if not an array.
      */
      */
-    public addUniform(name: string, size: number | number[]) {
+    public addUniform(name: string, size: number | number[], arraySize = 0) {
         if (this._noUBO) {
         if (this._noUBO) {
             return;
             return;
         }
         }
@@ -255,20 +276,45 @@ export class UniformBuffer {
         // This function must be called in the order of the shader layout !
         // This function must be called in the order of the shader layout !
         // size can be the size of the uniform, or data directly
         // size can be the size of the uniform, or data directly
         var data;
         var data;
-        if (size instanceof Array) {
-            data = size;
-            size = data.length;
-        } else {
-            size = <number>size;
-            data = [];
 
 
+        // std140 FTW...
+        if (arraySize > 0) {
+            if (size instanceof Array) {
+                throw "addUniform should not be use with Array in UBO: " + name;
+            }
+
+            this._uniformArraySizes[name] = { strideSize: size, arraySize };
+            if (size == 16) {
+                size = size * arraySize;
+            }
+            else {
+                const perElementPadding =  4 - size;
+                const totalPadding =  perElementPadding * arraySize;
+                size = size * arraySize + totalPadding;
+            }
+
+            data = [];
             // Fill with zeros
             // Fill with zeros
             for (var i = 0; i < size; i++) {
             for (var i = 0; i < size; i++) {
                 data.push(0);
                 data.push(0);
             }
             }
         }
         }
+        else {
+            if (size instanceof Array) {
+                data = size;
+                size = data.length;
+            } else {
+                size = <number>size;
+                data = [];
+
+                // Fill with zeros
+                for (var i = 0; i < size; i++) {
+                    data.push(0);
+                }
+            }
+            this._fillAlignment(<number>size);
+        }
 
 
-        this._fillAlignment(<number>size);
         this._uniformSizes[name] = <number>size;
         this._uniformSizes[name] = <number>size;
         this._uniformLocations[name] = this._uniformLocationPointer;
         this._uniformLocations[name] = this._uniformLocationPointer;
         this._uniformLocationPointer += <number>size;
         this._uniformLocationPointer += <number>size;
@@ -458,6 +504,55 @@ export class UniformBuffer {
         }
         }
     }
     }
 
 
+    /**
+     * Updates the value of an uniform. The `update` method must be called afterwards to make it effective in the GPU.
+     * @param uniformName Define the name of the uniform, as used in the uniform block in the shader.
+     * @param data Define the flattened data
+     * @param size Define the size of the data.
+     */
+    public updateUniformArray(uniformName: string, data: FloatArray, size: number) {
+
+        var location = this._uniformLocations[uniformName];
+        if (location === undefined) {
+            Logger.Error("Cannot add an uniform Array dynamically. Please, add it using addUniform.");
+            return;
+        }
+
+        if (!this._buffer) {
+            this.create();
+        }
+
+        const arraySizes = this._uniformArraySizes[uniformName];
+
+        if (!this._dynamic) {
+            // Cache for static uniform buffers
+            var changed = false;
+            let countToFour = 0;
+            let baseStride = 0;
+            for (var i = 0; i < size; i++) {
+                if (this._bufferData[location + baseStride * 4 + countToFour] !== data[i]) {
+                    changed = true;
+                    this._bufferData[location + baseStride * 4 + countToFour] = data[i];
+                }
+                countToFour++;
+                if (countToFour === arraySizes.strideSize) {
+                    for (; countToFour < 4; countToFour++) {
+                        this._bufferData[location + baseStride * 4 + countToFour] = 0;
+                    }
+                    countToFour = 0;
+                    baseStride++;
+                }
+            }
+
+            this._needSync = this._needSync || changed;
+        } else {
+            // No cache for dynamic
+            for (var i = 0; i < size; i++) {
+                this._bufferData[location + i] = data[i];
+            }
+        }
+    }
+
     // Update methods
     // Update methods
 
 
     private _updateMatrix3x3ForUniform(name: string, matrix: Float32Array): void {
     private _updateMatrix3x3ForUniform(name: string, matrix: Float32Array): void {
@@ -535,6 +630,14 @@ export class UniformBuffer {
         this.updateUniform(name, UniformBuffer._tempBuffer, 4);
         this.updateUniform(name, UniformBuffer._tempBuffer, 4);
     }
     }
 
 
+    private _updateFloatArrayForEffect(name: string, array: Float32Array) {
+        this._currentEffect.setFloatArray(name, array);
+    }
+
+    private _updateFloatArrayForUniform(name: string, array: Float32Array) {
+        this.updateUniformArray(name, array, array.length);
+    }
+
     private _updateMatrixForEffect(name: string, mat: IMatrixLike) {
     private _updateMatrixForEffect(name: string, mat: IMatrixLike) {
         this._currentEffect.setMatrix(name, mat);
         this._currentEffect.setMatrix(name, mat);
     }
     }
@@ -543,6 +646,14 @@ export class UniformBuffer {
         this.updateUniform(name, <any>mat.toArray(), 16);
         this.updateUniform(name, <any>mat.toArray(), 16);
     }
     }
 
 
+    private _updateMatricesForEffect(name: string, mat: Float32Array) {
+        this._currentEffect.setMatrices(name, mat);
+    }
+
+    private _updateMatricesForUniform(name: string, mat: Float32Array) {
+        this.updateUniform(name, mat, mat.length);
+    }
+
     private _updateVector3ForEffect(name: string, vector: Vector3) {
     private _updateVector3ForEffect(name: string, vector: Vector3) {
         this._currentEffect.setVector3(name, vector);
         this._currentEffect.setVector3(name, vector);
     }
     }