瀏覽代碼

Export Toon Map from MMDLoader

Takahiro 8 年之前
父節點
當前提交
718d48313f

+ 25 - 118
examples/js/loaders/MMDLoader.js

@@ -51,6 +51,7 @@ THREE.MMDLoader.prototype.constructor = THREE.MMDLoader;
 THREE.MMDLoader.prototype.setDefaultTexturePath = function ( path ) {
 
 	this.defaultTexturePath = path;
+	if ( this.defaultTexturePath.lastIndexOf( '/' ) !== this.defaultTexturePath.length - 1 ) this.defaultTexturePath += '/';
 
 };
 
@@ -2003,7 +2004,7 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 		var offset = 0;
 		var materialParams = [];
 
-		function loadTexture ( filePath, params ) {
+		function loadTexture( filePath, params ) {
 
 			if ( params === undefined ) {
 
@@ -2024,7 +2025,7 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 			var texture = loader.load( fullPath, function ( t ) {
 
-				t.flipY = false;
+				t.flipY = ( params.isToonTexture === true ) ? true : false;
 				t.wrapS = THREE.RepeatWrapping;
 				t.wrapT = THREE.RepeatWrapping;
 
@@ -2205,17 +2206,11 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 		}
 
-		var shader = THREE.ShaderLib[ 'mmd' ];
-
 		for ( var i = 0; i < materialParams.length; i++ ) {
 
 			var p = materialParams[ i ];
 			var p2 = model.materials[ i ];
-			var m = new THREE.ShaderMaterial( {
-				uniforms: THREE.UniformsUtils.clone( shader.uniforms ),
-				vertexShader: shader.vertexShader,
-				fragmentShader: shader.fragmentShader
-			} );
+			var m = new THREE.MeshPhongMaterial();
 
 			m.faceOffset = p.faceOffset;
 			m.faceNum = p.faceNum;
@@ -2350,7 +2345,6 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 				}
 
 				m.map = getTexture( p.map, textures );
-				m.uniforms.map.value = m.map;
 				checkTextureTransparency( m );
 
 			}
@@ -2358,7 +2352,6 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 			if ( p.envMap !== undefined ) {
 
 				m.envMap = getTexture( p.envMap, textures );
-				m.uniforms.envMap.value = m.envMap;
 				m.combine = p.envMapType;
 
 				// TODO: WebGLRenderer should automatically update?
@@ -2370,17 +2363,17 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 			}
 
-			m.uniforms.opacity.value = p.opacity;
-			m.uniforms.diffuse.value.copy( p.color );
+			m.opacity = p.opacity;
+			m.color = p.color;
 
 			if ( p.emissive !== undefined ) {
 
-				m.uniforms.emissive.value.copy( p.emissive );
+				m.emissive = p.emissive;
 
 			}
 
-			m.uniforms.specular.value.copy( p.specular );
-			m.uniforms.shininess.value = Math.max( p.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )
+			m.specular = p.specular;
+			m.shininess = Math.max( p.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )
 
 			if ( model.metadata.format === 'pmd' ) {
 
@@ -2404,21 +2397,10 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 				if ( m.outlineParameters.thickness === 0.0 ) m.outlineParameters.visible = false;
 
-				m.uniforms.toonMap.value = textures[ p2.toonIndex ];
-				m.uniforms.celShading.value = 1;
-
-				if ( p2.toonIndex === -1 ) {
-
-					m.uniforms.hasToonTexture.value = 0;
-
-				} else {
-
-					var n = model.toonTextures[ p2.toonIndex ].fileName;
-					var uuid = loadTexture( n, { defaultTexturePath: isDefaultToonTexture( n ) } );
-					m.uniforms.toonMap.value = textures[ uuid ];
-					m.uniforms.hasToonTexture.value = 1;
-
-				}
+				var toonFileName = ( p2.toonIndex === -1 ) ? 'toon00.bmp' : model.toonTextures[ p2.toonIndex ].fileName;
+				var uuid = loadTexture( toonFileName, { isToonTexture: true, defaultTexturePath: isDefaultToonTexture( toonFileName ) } );
+				m.toonMap = getTexture( uuid, textures );
+				m.toonMapDirectionY = true;
 
 			} else {
 
@@ -2430,33 +2412,25 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 				if ( m.outlineParameters.thickness === 0.0 ) m.outlineParameters.visible = false;
 
-				m.uniforms.celShading.value = 1;
+				var toonFileName, isDefaultToon;
 
-				if ( p2.toonIndex === -1 ) {
+				if ( p2.toonIndex === -1 || p2.toonFlag !== 0 ) {
 
-					m.uniforms.hasToonTexture.value = 0;
+					var num = p2.toonIndex + 1;
+					toonFileName = 'toon' + ( num < 10 ? '0' + num : num ) + '.bmp';
+					isDefaultToon = true;
 
 				} else {
 
-					if ( p2.toonFlag === 0 ) {
-
-						var n = model.textures[ p2.toonIndex ];
-						var uuid = loadTexture( n );
-						m.uniforms.toonMap.value = textures[ uuid ];
-
-					} else {
-
-						var num = p2.toonIndex + 1;
-						var fileName = 'toon' + ( num < 10 ? '0' + num : num ) + '.bmp';
-						var uuid = loadTexture( fileName, { defaultTexturePath: true } );
-						m.uniforms.toonMap.value = textures[ uuid ];
-
-					}
-
-					m.uniforms.hasToonTexture.value = 1;
+					toonFileName = model.textures[ p2.toonIndex ];
+					isDefaultToon = false;
 
 				}
 
+				var uuid = loadTexture( toonFileName, { isToonTexture: true, defaultTexturePath: isDefaultToon } );
+				m.toonMap = getTexture( uuid, textures );
+				m.toonMapDirectionY = true;
+
 			}
 
 			material.materials.push( m );
@@ -2485,7 +2459,7 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 					var m = material.materials[ e.index ];
 
-					if ( m.uniforms.opacity.value !== e.diffuse[ 3 ] ) {
+					if ( m.opacity !== e.diffuse[ 3 ] ) {
 
 						m.transparent = true;
 
@@ -3565,73 +3539,6 @@ THREE.MMDLoader.DataView.prototype = {
 
 };
 
-/*
- * Shaders are copied from MeshPhongMaterial and then MMD spcific codes are inserted.
- * Keep shaders updated on MeshPhongMaterial.
- */
-THREE.ShaderLib[ 'mmd' ] = {
-
-	uniforms: THREE.UniformsUtils.merge( [
-
-		THREE.ShaderLib[ 'phong' ].uniforms,
-
-		// MMD specific for toon mapping
-		{
-			"celShading"      : { type: "i", value: 0 },
-			"toonMap"         : { type: "t", value: null },
-			"hasToonTexture"  : { type: "i", value: 0 }
-		}
-
-	] ),
-
-	vertexShader: THREE.ShaderLib[ 'phong' ].vertexShader,
-
-	// put toon mapping logic right before "void main() {...}"
-	fragmentShader: THREE.ShaderLib[ 'phong' ].fragmentShader.replace( /void\s+main\s*\(\s*\)/, [
-
-		"	uniform bool celShading;",
-		"	uniform sampler2D toonMap;",
-		"	uniform bool hasToonTexture;",
-
-		"	vec3 toon ( vec3 lightDirection, vec3 norm ) {",
-		"		if ( ! hasToonTexture ) {",
-		"			return vec3( 1.0 );",
-		"		}",
-		"		vec2 coord = vec2( 0.0, 0.5 * ( 1.0 - dot( lightDirection, norm ) ) );",
-		"		return texture2D( toonMap, coord ).rgb;",
-		"	}",
-
-		// redefine for MMD
-		"#undef RE_Direct",
-		"void RE_Direct_BlinnMMD( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {",
-		"	float dotNL = saturate( dot( geometry.normal, directLight.direction ) );",
-		"	vec3 irradiance = dotNL * directLight.color;",
-
-		"	#ifndef PHYSICALLY_CORRECT_LIGHTS",
-
-		"		irradiance *= PI; // punctual light",
-
-		"	#endif",
-
-		// ---- MMD specific for toon mapping
-		"	if ( celShading ) {",
-		"		reflectedLight.directDiffuse += material.diffuseColor * directLight.color * toon( directLight.direction, geometry.normal );",
-		"	} else {",
-		"		reflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );",
-		"	}",
-		// ---- MMD specific for toon mapping
-
-		"	reflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;",
-		"}",
-		// ---- MMD specific for toon mapping
-		"#define RE_Direct	RE_Direct_BlinnMMD",
-		// ---- MMD specific for toon mapping
-
-		"void main()",
-
-	].join( "\n" ) )
-
-};
 
 THREE.MMDAudioManager = function ( audio, listener, p ) {
 

+ 2 - 2
examples/webgl_loader_mmd.html

@@ -76,10 +76,10 @@
 
 				scene = new THREE.Scene();
 
-				var ambient = new THREE.AmbientLight( 0x666666 );
+				var ambient = new THREE.AmbientLight( 0x444444 );
 				scene.add( ambient );
 
-				var directionalLight = new THREE.DirectionalLight( 0x887766 );
+				var directionalLight = new THREE.DirectionalLight( 0x888888 );
 				directionalLight.position.set( -1, 1, 1 ).normalize();
 				scene.add( directionalLight );
 

+ 7 - 0
src/materials/Material.js

@@ -198,6 +198,13 @@ Material.prototype = {
 
 		}
 
+		if ( this.toonMap && this.toonMap.isTexture ) {
+
+			data.toonMap = this.toonMap.toJSON( meta ).uuid;
+			data.toonMapDirectionY = this.toonMapDirectionY;
+
+		}
+
 		if ( this.size !== undefined ) data.size = this.size;
 		if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation;
 

+ 6 - 0
src/materials/MeshPhongMaterial.js

@@ -44,6 +44,9 @@ import { Color } from '../math/Color';
  *  reflectivity: <float>,
  *  refractionRatio: <float>,
  *
+ *  toonMap: new THREE.Texture( <Image> ),
+ *  toonMapDirectonY: <bool>,
+ *
  *  wireframe: <boolean>,
  *  wireframeLinewidth: <float>,
  *
@@ -94,6 +97,9 @@ function MeshPhongMaterial( parameters ) {
 	this.reflectivity = 1;
 	this.refractionRatio = 0.98;
 
+	this.toonMap = null;
+	this.toonMapDirectionY = false;
+
 	this.wireframe = false;
 	this.wireframeLinewidth = 1;
 	this.wireframeLinecap = 'round';

+ 6 - 0
src/renderers/WebGLRenderer.js

@@ -2183,6 +2183,12 @@ function WebGLRenderer( parameters ) {
 
 		}
 
+		if ( material.toonMap ) {
+
+			uniforms.toonMap.value = material.toonMap;
+
+		}
+
 	}
 
 	function refreshUniformsStandard( uniforms, material ) {

+ 2 - 0
src/renderers/shaders/ShaderChunk.js

@@ -72,6 +72,7 @@ import specularmap_fragment from './ShaderChunk/specularmap_fragment.glsl';
 import specularmap_pars_fragment from './ShaderChunk/specularmap_pars_fragment.glsl';
 import tonemapping_fragment from './ShaderChunk/tonemapping_fragment.glsl';
 import tonemapping_pars_fragment from './ShaderChunk/tonemapping_pars_fragment.glsl';
+import toonmap_pars_fragment from './ShaderChunk/toonmap_pars_fragment.glsl';
 import uv_pars_fragment from './ShaderChunk/uv_pars_fragment.glsl';
 import uv_pars_vertex from './ShaderChunk/uv_pars_vertex.glsl';
 import uv_vertex from './ShaderChunk/uv_vertex.glsl';
@@ -180,6 +181,7 @@ export var ShaderChunk = {
 	specularmap_pars_fragment: specularmap_pars_fragment,
 	tonemapping_fragment: tonemapping_fragment,
 	tonemapping_pars_fragment: tonemapping_pars_fragment,
+	toonmap_pars_fragment: toonmap_pars_fragment,
 	uv_pars_fragment: uv_pars_fragment,
 	uv_pars_vertex: uv_pars_vertex,
 	uv_vertex: uv_vertex,

+ 9 - 2
src/renderers/shaders/ShaderChunk/lights_phong_pars_fragment.glsl

@@ -18,9 +18,16 @@ struct BlinnPhongMaterial {
 
 void RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {
 
-	float dotNL = saturate( dot( geometry.normal, directLight.direction ) );
+	#ifdef USE_TOONMAP
 
-	vec3 irradiance = dotNL * directLight.color;
+		vec3 irradiance = getToonIrradiance( geometry.normal, directLight.direction ) * directLight.color;
+
+	#else
+
+		float dotNL = saturate( dot( geometry.normal, directLight.direction ) );
+		vec3 irradiance = dotNL * directLight.color;
+
+	#endif
 
 	#ifndef PHYSICALLY_CORRECT_LIGHTS
 

+ 23 - 0
src/renderers/shaders/ShaderChunk/toonmap_pars_fragment.glsl

@@ -0,0 +1,23 @@
+#ifdef USE_TOONMAP
+
+	uniform sampler2D toonMap;
+
+	vec3 getToonIrradiance( vec3 normal, vec3 lightDirection ) {
+
+		// dotNL will be from -1.0 to 1.0
+		float dotNL = dot( normal, lightDirection );
+
+		#ifdef TOONMAP_DIRECTION_Y
+
+			vec2 coord = vec2( 0.0, dotNL * 0.5 + 0.5 );
+
+		#else
+
+			vec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );
+
+		#endif
+
+		return texture2D( toonMap, coord ).rgb;
+
+	}
+#endif

+ 1 - 0
src/renderers/shaders/ShaderLib.js

@@ -60,6 +60,7 @@ var ShaderLib = {
 			UniformsLib.bumpmap,
 			UniformsLib.normalmap,
 			UniformsLib.displacementmap,
+			UniformsLib.toonmap,
 			UniformsLib.fog,
 			UniformsLib.lights,
 

+ 1 - 0
src/renderers/shaders/ShaderLib/meshphong_frag.glsl

@@ -17,6 +17,7 @@ uniform float opacity;
 #include <lightmap_pars_fragment>
 #include <emissivemap_pars_fragment>
 #include <envmap_pars_fragment>
+#include <toonmap_pars_fragment>
 #include <fog_pars_fragment>
 #include <bsdfs>
 #include <lights_pars>

+ 6 - 0
src/renderers/shaders/UniformsLib.js

@@ -80,6 +80,12 @@ var UniformsLib = {
 
 	},
 
+	toonmap: {
+
+		toonMap: { value: null }
+
+	},
+
 	fog: {
 
 		fogDensity: { value: 0.00025 },

+ 3 - 0
src/renderers/webgl/WebGLProgram.js

@@ -445,6 +445,9 @@ function WebGLProgram( renderer, code, material, parameters ) {
 			parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
 			parameters.vertexColors ? '#define USE_COLOR' : '',
 
+			parameters.toonMap ? '#define USE_TOONMAP' : '',
+			parameters.toonMapDirectionY ? '#define TOONMAP_DIRECTION_Y' : '',
+
 			parameters.flatShading ? '#define FLAT_SHADED' : '',
 
 			parameters.doubleSided ? '#define DOUBLE_SIDED' : '',

+ 4 - 1
src/renderers/webgl/WebGLPrograms.js

@@ -25,7 +25,7 @@ function WebGLPrograms( renderer, capabilities ) {
 	var parameterNames = [
 		"precision", "supportsVertexTextures", "map", "mapEncoding", "envMap", "envMapMode", "envMapEncoding",
 		"lightMap", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "displacementMap", "specularMap",
-		"roughnessMap", "metalnessMap",
+		"roughnessMap", "metalnessMap", "toonMap",
 		"alphaMap", "combine", "vertexColors", "fog", "useFog", "fogExp",
 		"flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning",
 		"maxBones", "useVertexTexture", "morphTargets", "morphNormals",
@@ -153,6 +153,9 @@ function WebGLPrograms( renderer, capabilities ) {
 			specularMap: !! material.specularMap,
 			alphaMap: !! material.alphaMap,
 
+			toonMap: !! material.toonMap,
+			toonMapDirectionY: !! material.toonMapDirectionY,
+
 			combine: material.combine,
 
 			vertexColors: material.vertexColors,