Prechádzať zdrojové kódy

Cleaned up skinning, made fallback to use uniforms if float vertex textures are not available.

For the moment bone texture size is hardcoded to 64 x 64 pixels (allowing for max 1024 bones). We'll see how it goes. I don't expect larger skeletons though it may be beneficial to have smaller textures for smaller skeletons.
alteredq 13 rokov pred
rodič
commit
1ec72fa678

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 111 - 111
build/Three.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 4 - 4
build/custom/ThreeWebGL.js


+ 31 - 8
src/objects/SkinnedMesh.js

@@ -7,6 +7,10 @@ THREE.SkinnedMesh = function ( geometry, material ) {
 
 	THREE.Mesh.call( this, geometry, material );
 
+	//
+
+	this.useVertexTexture = true;
+
 	// init bones
 
 	this.identityMatrix = new THREE.Matrix4();
@@ -62,14 +66,29 @@ THREE.SkinnedMesh = function ( geometry, material ) {
 
 		}
 
-		//this.boneMatrices = new Float32Array( 16 * this.bones.length );
+		//
+
+		if ( this.useVertexTexture ) {
+
+			// layout (1 matrix = 4 pixels)
+			//	RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
+			//  with 64x64 pixel texture max 1024 bones (64 * 64 / 4)
 
-		this.boneMatrices = new Float32Array( 64 * 64 * 4 ); // max 1024 bones
-		this.boneTexture = new THREE.DataTexture( this.boneMatrices, 64, 64, THREE.RGBAFormat, THREE.FloatType );
-		this.boneTexture.minFilter = THREE.NearestFilter;
-		this.boneTexture.magFilter = THREE.NearestFilter;
-		this.boneTexture.generateMipmaps = false;
-		this.boneTexture.flipY = false;
+			this.boneTextureWidth = 64;
+			this.boneTextureHeight = 64;
+
+			this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel
+			this.boneTexture = new THREE.DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, THREE.RGBAFormat, THREE.FloatType );
+			this.boneTexture.minFilter = THREE.NearestFilter;
+			this.boneTexture.magFilter = THREE.NearestFilter;
+			this.boneTexture.generateMipmaps = false;
+			this.boneTexture.flipY = false;
+
+		} else {
+
+			this.boneMatrices = new Float32Array( 16 * this.bones.length );
+
+		}
 
 		this.pose();
 
@@ -147,7 +166,11 @@ THREE.SkinnedMesh.prototype.updateMatrixWorld = function ( force ) {
 
 	}
 
-	this.boneTexture.needsUpdate = true;
+	if ( this.useVertexTexture ) {
+
+		this.boneTexture.needsUpdate = true;
+
+	}
 
 };
 

+ 56 - 36
src/renderers/WebGLRenderer.js

@@ -183,6 +183,9 @@ THREE.WebGLRenderer = function ( parameters ) {
 	_maxTextureSize = _gl.getParameter( _gl.MAX_TEXTURE_SIZE ),
 	_maxCubemapSize = _gl.getParameter( _gl.MAX_CUBE_MAP_TEXTURE_SIZE );
 
+	var _supportsVertexTextures = ( _maxVertexTextures > 0 );
+	var _supportsBoneTextures = _supportsVertexTextures && _glExtensionTextureFloat;
+
 	// API
 
 	this.getContext = function () {
@@ -193,7 +196,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	this.supportsVertexTextures = function () {
 
-		return _maxVertexTextures > 0;
+		return _supportsVertexTextures;
 
 	};
 
@@ -4794,19 +4797,27 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		if ( material.skinning ) {
 
-			/*
-			if ( p_uniforms.boneGlobalMatrices !== null ) {
+			if ( _supportsBoneTextures ) {
 
-				_gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.boneMatrices );
+				if ( p_uniforms.boneTexture !== null ) {
 
-			}
-			*/
+					// shadowMap texture array starts from 6
+					// texture unit 12 should leave space for 6 shadowmaps
+
+					var textureUnit = 12;
+
+					_gl.uniform1i( p_uniforms.boneTexture, textureUnit );
+					_this.setTexture( object.boneTexture, textureUnit );
+
+				}
+
+			} else {
+
+				if ( p_uniforms.boneGlobalMatrices !== null ) {
 
-			if ( p_uniforms.boneTexture !== null ) {
+					_gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.boneMatrices );
 
-				var textureUnit = 12; // shadowMap texture array starts from 6, 12 should leave space for 6 shadowmaps
-				_gl.uniform1i( p_uniforms.boneTexture, textureUnit );
-				_this.setTexture( object.boneTexture, textureUnit );
+				}
 
 			}
 
@@ -5665,7 +5676,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 			"precision " + _precision + " float;",
 
-			( _maxVertexTextures > 0 ) ? "#define VERTEX_TEXTURES" : "",
+			_supportsVertexTextures ? "#define VERTEX_TEXTURES" : "",
 
 			_this.gammaInput ? "#define GAMMA_INPUT" : "",
 			_this.gammaOutput ? "#define GAMMA_OUTPUT" : "",
@@ -5683,7 +5694,10 @@ THREE.WebGLRenderer = function ( parameters ) {
 			parameters.envMap ? "#define USE_ENVMAP" : "",
 			parameters.lightMap ? "#define USE_LIGHTMAP" : "",
 			parameters.vertexColors ? "#define USE_COLOR" : "",
+
 			parameters.skinning ? "#define USE_SKINNING" : "",
+			_supportsBoneTextures ? "#define BONE_TEXTURE" : "",
+
 			parameters.morphTargets ? "#define USE_MORPHTARGETS" : "",
 			parameters.morphNormals ? "#define USE_MORPHNORMALS" : "",
 			parameters.perPixel ? "#define PHONG_PER_PIXEL" : "",
@@ -5825,12 +5839,20 @@ THREE.WebGLRenderer = function ( parameters ) {
 		identifiers = [
 
 			'viewMatrix', 'modelViewMatrix', 'projectionMatrix', 'normalMatrix', 'objectMatrix', 'cameraPosition',
-			//'boneGlobalMatrices',
-			'boneTexture',
 			'morphTargetInfluences'
 
 		];
 
+		if ( _supportsBoneTextures ) {
+
+			identifiers.push( 'boneTexture' );
+
+		} else {
+
+			identifiers.push( 'boneGlobalMatrices' );
+
+		}
+
 		for ( u in uniforms ) {
 
 			identifiers.push( u );
@@ -6364,43 +6386,41 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	function allocateBones ( object ) {
 
-		// default for when object is not specified
-		// ( for example when prebuilding shader
-		//   to be used with multiple objects )
-		//
-		// 	- leave some extra space for other uniforms
-		//  - limit here is ANGLE's 254 max uniform vectors
-		//    (up to 54 should be safe)
+		if ( _supportsBoneTextures ) {
+
+			return 1024;
 
-		/*
-		var nVertexUniforms = _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS );
-		var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );
+		} else {
 
-		var maxBones = nVertexMatrices;
+			// default for when object is not specified
+			// ( for example when prebuilding shader
+			//   to be used with multiple objects )
+			//
+			// 	- leave some extra space for other uniforms
+			//  - limit here is ANGLE's 254 max uniform vectors
+			//    (up to 54 should be safe)
 
-		if ( object !== undefined && object instanceof THREE.SkinnedMesh ) {
+			var nVertexUniforms = _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS );
+			var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );
 
-			maxBones = Math.min( object.bones.length, maxBones );
+			var maxBones = nVertexMatrices;
 
-			if ( maxBones < object.bones.length ) {
+			if ( object !== undefined && object instanceof THREE.SkinnedMesh ) {
 
-				console.warn( "WebGLRenderer: too many bones - " + object.bones.length + ", this GPU supports just " + maxBones + " (try OpenGL instead of ANGLE)" );
+				maxBones = Math.min( object.bones.length, maxBones );
 
-			}
+				if ( maxBones < object.bones.length ) {
 
-		}
-		*/
+					console.warn( "WebGLRenderer: too many bones - " + object.bones.length + ", this GPU supports just " + maxBones + " (try OpenGL instead of ANGLE)" );
 
-		var maxBones = 0;
+				}
 
-		if ( object !== undefined && object instanceof THREE.SkinnedMesh ) {
+			}
 
-			maxBones = object.bones.length;
+			return maxBones;
 
 		}
 
-		return maxBones;
-
 	};
 
 	function allocateLights ( lights ) {

+ 32 - 26
src/renderers/WebGLShaders.js

@@ -957,33 +957,47 @@ THREE.ShaderChunk = {
 
 		"#ifdef USE_SKINNING",
 
-			//"uniform mat4 boneGlobalMatrices[ MAX_BONES ];",
-			"uniform sampler2D boneTexture;",
+			"#ifdef BONE_TEXTURE",
 
-			"#define N_SKIN_PIXEL_X 64.0",
-			"#define N_SKIN_PIXEL_Y 64.0",
+				"uniform sampler2D boneTexture;",
 
-			"mat4 getBoneMatrix( const in float i ) {",
+				"#define N_SKIN_PIXEL_X 64.0",
+				"#define N_SKIN_PIXEL_Y 64.0",
 
-				"float j = i * 4.0;",
-				"float x = mod( j, N_SKIN_PIXEL_X );",
-				"float y = floor( j / N_SKIN_PIXEL_X );",
+				"mat4 getBoneMatrix( const in float i ) {",
 
-				"const float dx = 1.0 / N_SKIN_PIXEL_X;",
-				"const float dy = 1.0 / N_SKIN_PIXEL_Y;",
+					"float j = i * 4.0;",
+					"float x = mod( j, N_SKIN_PIXEL_X );",
+					"float y = floor( j / N_SKIN_PIXEL_X );",
 
-				"y = dy * ( y + 0.5 );",
+					"const float dx = 1.0 / N_SKIN_PIXEL_X;",
+					"const float dy = 1.0 / N_SKIN_PIXEL_Y;",
 
-				"vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );",
-				"vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );",
-				"vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );",
-				"vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );",
+					"y = dy * ( y + 0.5 );",
 
-				"mat4 bone = mat4( v1, v2, v3, v4 );",
+					"vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );",
+					"vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );",
+					"vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );",
+					"vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );",
 
-				"return bone;",
+					"mat4 bone = mat4( v1, v2, v3, v4 );",
 
-			"}",
+					"return bone;",
+
+				"}",
+
+			"#else",
+
+				"uniform mat4 boneGlobalMatrices[ MAX_BONES ];",
+
+				"mat4 getBoneMatrix( const in float i ) {",
+
+					"mat4 bone = boneGlobalMatrices[ int(i) ];",
+					"return bone;",
+
+				"}",
+
+			"#endif",
 
 		"#endif"
 
@@ -1007,9 +1021,6 @@ THREE.ShaderChunk = {
 			"vec4 skinned  = boneMatX * skinVertexA * skinWeight.x;",
 			"skinned 	  += boneMatY * skinVertexB * skinWeight.y;",
 
-			//"vec4 skinned  = ( boneGlobalMatrices[ int( skinIndex.x ) ] * skinVertexA ) * skinWeight.x;",
-			//"skinned 	  += ( boneGlobalMatrices[ int( skinIndex.y ) ] * skinVertexB ) * skinWeight.y;",
-
 			"gl_Position  = projectionMatrix * modelViewMatrix * skinned;",
 
 		"#endif"
@@ -1102,11 +1113,6 @@ THREE.ShaderChunk = {
 
 		"#ifdef USE_SKINNING",
 
-			/*
-			"mat4 skinMatrix = skinWeight.x * boneGlobalMatrices[ int( skinIndex.x ) ];",
-			"skinMatrix 	+= skinWeight.y * boneGlobalMatrices[ int( skinIndex.y ) ];",
-			*/
-
 			"mat4 skinMatrix = skinWeight.x * boneMatX;",
 			"skinMatrix 	+= skinWeight.y * boneMatY;",
 

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov