Răsfoiți Sursa

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 ani în urmă
părinte
comite
1ec72fa678

Fișier diff suprimat deoarece este prea mare
+ 111 - 111
build/Three.js


Fișier diff suprimat deoarece este prea mare
+ 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;",
 

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff