Jelajahi Sumber

fix programs sharing multiple ubo and support array uniforms (#25084)

Renaud Rohlinger 2 tahun lalu
induk
melakukan
3e97fb1cab

+ 39 - 6
examples/webgl2_ubo.html

@@ -88,23 +88,30 @@
 
 		<script id="vertexShader2" type="x-shader/x-vertex">
 
-			uniform ViewData {
+			layout(std140) uniform ViewData {
 				mat4 projectionMatrix;
 				mat4 viewMatrix;
 			};
 
 			uniform mat4 modelMatrix;
+			uniform mat3 normalMatrix;
 
 			in vec3 position;
+			in vec3 normal;
 			in vec2 uv;
 
+			out vec3 vPositionEye;
+			out vec3 vNormalEye;
 			out vec2 vUv;
 
 			void main()	{
 
-				vUv = uv;
+				vec4 vertexPositionEye = viewMatrix * modelMatrix * vec4( position, 1.0 );
 
-				gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( position, 1.0 );
+				vPositionEye = vertexPositionEye.xyz;
+				vNormalEye = normalMatrix * normal;
+				vUv = uv;
+				gl_Position = projectionMatrix * vertexPositionEye;
 
 			}
 
@@ -117,12 +124,38 @@
 			uniform sampler2D diffuseMap;
 
 			in vec2 vUv;
-
+			in vec3 vPositionEye;
+			in vec3 vNormalEye;
 			out vec4 fragColor;
 
+			uniform LightingData {
+				vec3 position;
+				vec3 ambientColor;
+				vec3 diffuseColor;
+				vec3 specularColor;
+				float shininess;
+			} Light;
+
 			void main()	{
 
-				fragColor = texture( diffuseMap, vUv );
+
+				// a very basic lighting equation (Phong reflection model) for testing
+
+				vec3 l = normalize( Light.position - vPositionEye );
+				vec3 n = normalize( vNormalEye );
+				vec3 e = - normalize( vPositionEye );
+				vec3 r = normalize( reflect( - l, n ) );
+
+				float diffuseLightWeighting = max( dot( n, l ), 0.0 );
+				float specularLightWeighting = max( dot( r, e ), 0.0 );
+
+				specularLightWeighting = pow( specularLightWeighting, Light.shininess );
+
+				vec3 lightWeighting = Light.ambientColor +
+					Light.diffuseColor * diffuseLightWeighting +
+					Light.specularColor * specularLightWeighting;
+
+				fragColor = vec4( texture( diffuseMap, vUv ).rgb * lightWeighting.rgb, 1.0 );
 
 			}
 
@@ -242,7 +275,7 @@
 
 						mesh = new THREE.Mesh( geometry2, material2.clone() );
 
-						mesh.material.uniformsGroups = [ cameraUniformsGroup ];
+						mesh.material.uniformsGroups = [ cameraUniformsGroup, lightingUniformsGroup ];
 						mesh.material.uniforms.modelMatrix.value = mesh.matrixWorld;
 						mesh.material.uniforms.diffuseMap.value = texture;
 

+ 6 - 7
src/renderers/webgl/WebGLState.js

@@ -307,7 +307,7 @@ function WebGLState( gl, extensions, capabilities ) {
 	const stencilBuffer = new StencilBuffer();
 
 	const uboBindings = new WeakMap();
-	const uboProgamMap = new WeakMap();
+	const uboProgramMap = new WeakMap();
 
 	let enabledCapabilities = {};
 
@@ -1104,13 +1104,13 @@ function WebGLState( gl, extensions, capabilities ) {
 
 	function updateUBOMapping( uniformsGroup, program ) {
 
-		let mapping = uboProgamMap.get( program );
+		let mapping = uboProgramMap.get( program );
 
 		if ( mapping === undefined ) {
 
 			mapping = new WeakMap();
 
-			uboProgamMap.set( program, mapping );
+			uboProgramMap.set( program, mapping );
 
 		}
 
@@ -1128,16 +1128,15 @@ function WebGLState( gl, extensions, capabilities ) {
 
 	function uniformBlockBinding( uniformsGroup, program ) {
 
-		const mapping = uboProgamMap.get( program );
+		const mapping = uboProgramMap.get( program );
 		const blockIndex = mapping.get( uniformsGroup );
 
-		if ( uboBindings.get( uniformsGroup ) !== blockIndex ) {
+		if ( uboBindings.get( program ) !== blockIndex ) {
 
 			// bind shader specific block index to global block point
-
 			gl.uniformBlockBinding( program, blockIndex, uniformsGroup.__bindingPointIndex );
 
-			uboBindings.set( uniformsGroup, blockIndex );
+			uboBindings.set( program, blockIndex );
 
 		}
 

+ 74 - 33
src/renderers/webgl/WebGLUniformsGroups.js

@@ -102,43 +102,52 @@ function WebGLUniformsGroups( gl, info, capabilities, state ) {
 
 			if ( hasUniformChanged( uniform, i, cache ) === true ) {
 
-				const value = uniform.value;
 				const offset = uniform.__offset;
 
-				if ( typeof value === 'number' ) {
+				const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ];
 
-					uniform.__data[ 0 ] = value;
-					gl.bufferSubData( gl.UNIFORM_BUFFER, offset, uniform.__data );
+				let arrayOffset = 0;
 
-				} else {
+				for ( let i = 0; i < values.length; i ++ ) {
 
-					if ( uniform.value.isMatrix3 ) {
+					const value = values[ i ];
+
+					const info = getUniformSize( value );
+
+					if ( typeof value === 'number' ) {
+
+						uniform.__data[ 0 ] = value;
+						gl.bufferSubData( gl.UNIFORM_BUFFER, offset + arrayOffset, uniform.__data );
+
+					} else if ( value.isMatrix3 ) {
 
 						// manually converting 3x3 to 3x4
 
-						uniform.__data[ 0 ] = uniform.value.elements[ 0 ];
-						uniform.__data[ 1 ] = uniform.value.elements[ 1 ];
-						uniform.__data[ 2 ] = uniform.value.elements[ 2 ];
-						uniform.__data[ 3 ] = uniform.value.elements[ 0 ];
-						uniform.__data[ 4 ] = uniform.value.elements[ 3 ];
-						uniform.__data[ 5 ] = uniform.value.elements[ 4 ];
-						uniform.__data[ 6 ] = uniform.value.elements[ 5 ];
-						uniform.__data[ 7 ] = uniform.value.elements[ 0 ];
-						uniform.__data[ 8 ] = uniform.value.elements[ 6 ];
-						uniform.__data[ 9 ] = uniform.value.elements[ 7 ];
-						uniform.__data[ 10 ] = uniform.value.elements[ 8 ];
-						uniform.__data[ 11 ] = uniform.value.elements[ 0 ];
+						uniform.__data[ 0 ] = value.elements[ 0 ];
+						uniform.__data[ 1 ] = value.elements[ 1 ];
+						uniform.__data[ 2 ] = value.elements[ 2 ];
+						uniform.__data[ 3 ] = value.elements[ 0 ];
+						uniform.__data[ 4 ] = value.elements[ 3 ];
+						uniform.__data[ 5 ] = value.elements[ 4 ];
+						uniform.__data[ 6 ] = value.elements[ 5 ];
+						uniform.__data[ 7 ] = value.elements[ 0 ];
+						uniform.__data[ 8 ] = value.elements[ 6 ];
+						uniform.__data[ 9 ] = value.elements[ 7 ];
+						uniform.__data[ 10 ] = value.elements[ 8 ];
+						uniform.__data[ 11 ] = value.elements[ 0 ];
 
 					} else {
 
-						value.toArray( uniform.__data );
+						value.toArray( uniform.__data, arrayOffset );
 
-					}
+						arrayOffset += info.storage / Float32Array.BYTES_PER_ELEMENT;
 
-					gl.bufferSubData( gl.UNIFORM_BUFFER, offset, uniform.__data );
+					}
 
 				}
 
+				gl.bufferSubData( gl.UNIFORM_BUFFER, offset, uniform.__data );
+
 			}
 
 		}
@@ -161,7 +170,17 @@ function WebGLUniformsGroups( gl, info, capabilities, state ) {
 
 			} else {
 
-				cache[ index ] = value.clone();
+				const values = Array.isArray( value ) ? value : [ value ];
+
+				const tempValues = [];
+
+				for ( let i = 0; i < values.length; i ++ ) {
+
+					tempValues.push( values[ i ].clone() );
+
+				}
+
+				cache[ index ] = tempValues;
 
 			}
 
@@ -182,12 +201,19 @@ function WebGLUniformsGroups( gl, info, capabilities, state ) {
 
 			} else {
 
-				const cachedObject = cache[ index ];
+				const cachedObjects = Array.isArray( cache[ index ] ) ? cache[ index ] : [ cache[ index ] ];
+				const values = Array.isArray( value ) ? value : [ value ];
 
-				if ( cachedObject.equals( value ) === false ) {
+				for ( let i = 0; i < cachedObjects.length; i ++ ) {
 
-					cachedObject.copy( value );
-					return true;
+					const cachedObject = cachedObjects[ i ];
+
+					if ( cachedObject.equals( values[ i ] ) === false ) {
+
+						cachedObject.copy( values[ i ] );
+						return true;
+
+					}
 
 				}
 
@@ -213,11 +239,28 @@ function WebGLUniformsGroups( gl, info, capabilities, state ) {
 		for ( let i = 0, l = uniforms.length; i < l; i ++ ) {
 
 			const uniform = uniforms[ i ];
-			const info = getUniformSize( uniform );
+
+			const infos = {
+				boundary: 0, // bytes
+				storage: 0 // bytes
+			};
+
+			const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ];
+
+			for ( let j = 0, jl = values.length; j < jl; j ++ ) {
+
+				const value = values[ j ];
+
+				const info = getUniformSize( value );
+
+				infos.boundary += info.boundary;
+				infos.storage += info.storage;
+
+			}
 
 			// the following two properties will be used for partial buffer updates
 
-			uniform.__data = new Float32Array( info.storage / Float32Array.BYTES_PER_ELEMENT );
+			uniform.__data = new Float32Array( infos.storage / Float32Array.BYTES_PER_ELEMENT );
 			uniform.__offset = offset;
 
 			//
@@ -230,7 +273,7 @@ function WebGLUniformsGroups( gl, info, capabilities, state ) {
 
 				// check for chunk overflow
 
-				if ( chunkOffset !== 0 && ( remainingSizeInChunk - info.boundary ) < 0 ) {
+				if ( chunkOffset !== 0 && ( remainingSizeInChunk - infos.boundary ) < 0 ) {
 
 					// add padding and adjust offset
 
@@ -241,7 +284,7 @@ function WebGLUniformsGroups( gl, info, capabilities, state ) {
 
 			}
 
-			offset += info.storage;
+			offset += infos.storage;
 
 		}
 
@@ -260,9 +303,7 @@ function WebGLUniformsGroups( gl, info, capabilities, state ) {
 
 	}
 
-	function getUniformSize( uniform ) {
-
-		const value = uniform.value;
+	function getUniformSize( value ) {
 
 		const info = {
 			boundary: 0, // bytes