diff --git a/examples/js/effects/OutlineEffect.js b/examples/js/effects/OutlineEffect.js new file mode 100644 index 0000000000000000000000000000000000000000..7c4907617ba7d1d0f16b4427607aa72ee3ebc0be --- /dev/null +++ b/examples/js/effects/OutlineEffect.js @@ -0,0 +1,294 @@ +/** + * @author takahirox / http://github.com/takahirox/ + * + * Reference: https://en.wikipedia.org/wiki/Cel_shading + * + * // How to set default outline parameters + * new THREE.OutlineEffect( renderer, { + * defaultThickNess: 0.01, + * defaultColor: new THREE.Color( 0x888888 ), + * defaultAlpha: 0.8 + * } ); + * + * // How to set outline parameters for each material + * material.outlineParameters = { + * thickNess: 0.01, + * color: new THREE.Color( 0x888888 ), + * alpha: 0.8, + * visible: true + * }; + * + * TODO + * - shared material + * - support shader material without objectNormal in its vertexShader + */ + +THREE.OutlineEffect = function ( renderer, parameters ) { + + var _this = this; + + parameters = parameters || {}; + + this.autoClear = parameters.autoClear !== undefined ? parameters.autoClear : true; + + var defaultThickness = parameters.defaultThickness !== undefined ? parameters.defaultThickness : 0.003; + var defaultColor = parameters.defaultColor !== undefined ? parameters.defaultColor : new THREE.Color( 0x000000 ); + var defaultAlpha = parameters.defaultAlpha !== undefined ? parameters.defaultAlpha : 1.0; + + var invisibleMaterial = new THREE.ShaderMaterial( { visible: false } ); + + // copied from WebGLPrograms and removed some materials + var shaderIDs = { + MeshBasicMaterial: 'basic', + MeshLambertMaterial: 'lambert', + MeshPhongMaterial: 'phong', + MeshStandardMaterial: 'physical', + MeshPhysicalMaterial: 'physical' + }; + + var uniformsChunk = { + outlineThickness: { type: "f", value: defaultThickness }, + outlineColor: { type: "c", value: defaultColor }, + outlineAlpha: { type: "f", value: defaultAlpha } + }; + + var vertexShaderChunk = [ + + "uniform float outlineThickness;", + + "vec4 calculateOutline( vec4 pos, vec3 objectNormal, vec4 skinned ) {", + + " float thickness = outlineThickness;", + " float ratio = 1.0;", // TODO: support outline thickness ratio for each vertex + " vec4 pos2 = projectionMatrix * modelViewMatrix * vec4( skinned.xyz + objectNormal, 1.0 );", + // NOTE: subtract pos2 from pos because BackSide objectNormal is negative + " vec4 norm = normalize( pos - pos2 );", + " return pos + norm * thickness * pos.w * ratio;", + + "}", + + ].join( "\n" ); + + var vertexShaderChunk2 = [ + + "#if ! defined( LAMBERT ) && ! defined( PHONG ) && ! defined( PHYSICAL )", + + " #ifndef USE_ENVMAP", + " vec3 objectNormal = normalize( normal );", + + " #ifdef FLIP_SIDED", + " objectNormal = -objectNormal;", + " #endif", + + " #endif", + + "#endif", + + "#ifdef USE_SKINNING", + " gl_Position = calculateOutline( gl_Position, objectNormal, skinned );", + "#else", + " gl_Position = calculateOutline( gl_Position, objectNormal, vec4( transformed, 1.0 ) );", + "#endif", + + ].join( "\n" ); + + var fragmentShader = [ + + "#include ", + "#include ", + + "uniform vec3 outlineColor;", + "uniform float outlineAlpha;", + + "void main() {", + + " gl_FragColor = vec4( outlineColor, outlineAlpha );", + + " #include ", + + "}", + + ].join( "\n" ); + + function createMaterial ( originalMaterial ) { + + var shaderID = shaderIDs[ originalMaterial.type ]; + var originalUniforms, originalVertexShader; + var outlineParameters = originalMaterial.outlineParameters; + + if ( shaderID !== undefined ) { + + var shader = THREE.ShaderLib[ shaderID ]; + originalUniforms = shader.uniforms; + originalVertexShader = shader.vertexShader; + + } else if ( originalMaterial.isShaderMaterial === true ) { + + originalUniforms = originalMaterial.uniforms; + originalVertexShader = originalMaterial.vertexShader; + + } else { + + return invisibleMaterial; + + } + + var uniforms = THREE.UniformsUtils.merge( [ + originalUniforms, + uniformsChunk + ] ); + + var vertexShader = originalVertexShader + // put vertexShaderChunk right before "void main() {...}" + .replace( /void\s+main\s*\(\s*\)/, vertexShaderChunk + '\nvoid main()' ) + // put vertexShaderChunk2 the end of "void main() {...}" + // Note: here assums originalVertexShader ends with "}" of "void main() {...}" + .replace( /\}\s*$/, vertexShaderChunk2 + '\n}' ) + // remove any light related lines + // Note: here is very sensitive to originalVertexShader + // TODO: consider safer way + .replace( /#include\s+<[\w_]*light[\w_]*>/g, '' ); + + var material = new THREE.ShaderMaterial( { + uniforms: THREE.UniformsUtils.clone( uniforms ), + vertexShader: vertexShader, + fragmentShader: fragmentShader, + side: THREE.BackSide, + //wireframe: true, + skinning: false, + morphTargets: false, + morphNormals: false, + fog: false + } ); + + return material; + + } + + function createMultiMaterial ( originalMaterial ) { + + var materials = []; + + for ( var i = 0, il = originalMaterial.materials.length; i < il; i ++ ) { + + materials.push( createMaterial( originalMaterial.materials[ i ] ) ); + + } + + return new THREE.MultiMaterial( materials ); + + } + + function setOutlineMaterial ( object ) { + + if ( object.material === undefined ) return; + + object.userData.originalMaterial = object.material; + + if ( object.userData.outlineMaterial === undefined ) { + + object.userData.outlineMaterial = object.material.type === 'MultiMaterial' ? createMultiMaterial( object.material ) : createMaterial( object.material ); + + } + + if ( object.userData.outlineMaterial.type === 'MultiMaterial' ) { + + updateOutlineMultiMaterial( object.userData.outlineMaterial, object.userData.originalMaterial ); + + } else { + + updateOutlineMaterial( object.userData.outlineMaterial, object.userData.originalMaterial ); + + } + + object.material = object.userData.outlineMaterial; + + } + + function updateOutlineMaterial ( material, originalMaterial ) { + + if ( material === invisibleMaterial ) return; + + var outlineParameters = originalMaterial.outlineParameters; + + material.skinning = originalMaterial.skinning; + material.morphTargets = originalMaterial.morphTargets; + material.morphNormals = originalMaterial.morphNormals; + material.fog = originalMaterial.fog; + material.visible = originalMaterial.visible; + material.uniforms.outlineAlpha.value = originalMaterial.opacity; + + if ( outlineParameters !== undefined ) { + + if ( outlineParameters.thickness !== undefined ) material.uniforms.outlineThickness.value = outlineParameters.thickness; + if ( outlineParameters.color !== undefined ) material.uniforms.outlineColor.value.copy( outlineParameters.color ); + if ( outlineParameters.alpha !== undefined ) material.uniforms.outlineAlpha.value = outlineParameters.alpha; + if ( outlineParameters.visible !== undefined ) material.visible = outlineParameters.visible; + + } + + if ( material.uniforms.outlineAlpha.value < 1.0 ) material.transparent = true; + + } + + function updateOutlineMultiMaterial ( material, originalMaterial ) { + + var outlineParameters = originalMaterial.outlineParameters; + + material.visible = originalMaterial.visible; + + if ( outlineParameters !== undefined ) { + + if ( outlineParameters.visible !== undefined ) material.visible = outlineParameters.visible; + + } + + for ( var i = 0, il = material.materials.length; i < il; i ++ ) { + + updateOutlineMaterial( material.materials[ i ], originalMaterial.materials[ i ] ); + + } + + } + + function restoreOriginalMaterial ( object ) { + + if ( object.userData.originalMaterial !== undefined ) object.material = object.userData.originalMaterial; + + } + + this.setSize = function ( width, height ) { + + renderer.setSize( width, height ); + + }; + + this.render = function ( scene, camera, renderTarget, forceClear ) { + + var currentAutoClear = renderer.autoClear; + renderer.autoClear = this.autoClear; + + // 1. render normally + renderer.render( scene, camera, renderTarget, forceClear ); + + // 2. render outline + var currentSceneAutoUpdate = scene.autoUpdate; + var currentShadowMapEnabled = renderer.shadowMap.enabled; + + scene.autoUpdate = false; + renderer.autoClear = false; + renderer.shadowMap.enabled = false; + + scene.traverse( setOutlineMaterial ); + + renderer.render( scene, camera, renderTarget ); + + scene.traverse( restoreOriginalMaterial ); + + scene.autoUpdate = currentSceneAutoUpdate; + renderer.autoClear = currentAutoClear; + renderer.shadowMap.enabled = currentShadowMapEnabled; + + }; + +}; diff --git a/examples/js/loaders/MMDLoader.js b/examples/js/loaders/MMDLoader.js index c3e35ece19b577b610b665aaedc219b2e06e9b57..42098439500ef2578ceec821a9483055d0b41197 100644 --- a/examples/js/loaders/MMDLoader.js +++ b/examples/js/loaders/MMDLoader.js @@ -3,7 +3,11 @@ * * Dependencies * - charset-encoder-js https://github.com/takahirox/charset-encoder-js + * - ammo.js https://github.com/kripken/ammo.js * - THREE.TGALoader + * - THREE.MMDPhysics + * - THREE.CCDIKSolver + * - THREE.OutlineEffect * * * This loader loads and parses PMD/PMX and VMD binary files @@ -2336,7 +2340,7 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress var imageData = t.image.data !== undefined ? t.image : createImageData( t.image ); var uvs = geometry.faceVertexUvs[ 0 ].slice( m.faceOffset, m.faceOffset + m.faceNum ); - m.textureTransparency = detectTextureTransparency( imageData, uvs ); + if ( detectTextureTransparency( imageData, uvs ) ) m.transparent = true; delete m.faceOffset; delete m.faceNum; @@ -2392,9 +2396,14 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress }; - m.uniforms.outlineThickness.value = p2.edgeFlag === 1 ? 0.003 : 0.0; - m.uniforms.outlineColor.value = new THREE.Color( 0.0, 0.0, 0.0 ); - m.uniforms.outlineAlpha.value = 1.0; + m.outlineParameters = { + thickness: p2.edgeFlag === 1 ? 0.003 : 0.0, + color: new THREE.Color( 0.0, 0.0, 0.0 ), + alpha: 1.0 + }; + + if ( m.outlineParameters.thickness === 0.0 ) m.outlineParameters.visible = false; + m.uniforms.toonMap.value = textures[ p2.toonIndex ]; m.uniforms.celShading.value = 1; @@ -2408,13 +2417,19 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress var uuid = loadTexture( n, { defaultTexturePath: isDefaultToonTexture( n ) } ); m.uniforms.toonMap.value = textures[ uuid ]; m.uniforms.hasToonTexture.value = 1; + } } else { - m.uniforms.outlineThickness.value = p2.edgeSize / 300; - m.uniforms.outlineColor.value = new THREE.Color( p2.edgeColor[ 0 ], p2.edgeColor[ 1 ], p2.edgeColor[ 2 ] ); - m.uniforms.outlineAlpha.value = p2.edgeColor[ 3 ]; + m.outlineParameters = { + thickness: p2.edgeSize / 300, + color: new THREE.Color( p2.edgeColor[ 0 ], p2.edgeColor[ 1 ], p2.edgeColor[ 2 ] ), + alpha: p2.edgeColor[ 3 ] + }; + + if ( m.outlineParameters.thickness === 0.0 ) m.outlineParameters.visible = false; + m.uniforms.celShading.value = 1; if ( p2.toonIndex === -1 ) { @@ -2472,7 +2487,7 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress if ( m.uniforms.opacity.value !== e.diffuse[ 3 ] ) { - m.morphTransparency = true; + m.transparent = true; } @@ -3558,148 +3573,22 @@ THREE.ShaderLib[ 'mmd' ] = { uniforms: THREE.UniformsUtils.merge( [ - THREE.UniformsLib[ "common" ], - THREE.UniformsLib[ "aomap" ], - THREE.UniformsLib[ "lightmap" ], - THREE.UniformsLib[ "emissivemap" ], - THREE.UniformsLib[ "bumpmap" ], - THREE.UniformsLib[ "normalmap" ], - THREE.UniformsLib[ "displacementmap" ], - THREE.UniformsLib[ "fog" ], - THREE.UniformsLib[ "lights" ], + THREE.ShaderLib[ 'phong' ].uniforms, + // MMD specific for toon mapping { - "emissive" : { value: new THREE.Color( 0x000000 ) }, - "specular" : { value: new THREE.Color( 0x111111 ) }, - "shininess": { value: 30 } - }, - - // ---- MMD specific for cel shading(outline drawing and toon mapping) - { - "outlineDrawing" : { value: 0 }, - "outlineThickness": { value: 0.0 }, - "outlineColor" : { value: new THREE.Color( 0x000000 ) }, - "outlineAlpha" : { value: 1.0 }, - "celShading" : { value: 0 }, - "toonMap" : { value: null }, - "hasToonTexture" : { value: 0 } + "celShading" : { type: "i", value: 0 }, + "toonMap" : { type: "t", value: null }, + "hasToonTexture" : { type: "i", value: 0 } } - // ---- MMD specific for cel shading(outline drawing and toon mapping) ] ), - vertexShader: [ - - "#define PHONG", - - "varying vec3 vViewPosition;", - - "#ifndef FLAT_SHADED", - - " varying vec3 vNormal;", - - "#endif", + vertexShader: THREE.ShaderLib[ 'phong' ].vertexShader, - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "uv_pars_vertex" ], - THREE.ShaderChunk[ "uv2_pars_vertex" ], - THREE.ShaderChunk[ "displacementmap_pars_vertex" ], - THREE.ShaderChunk[ "envmap_pars_vertex" ], - THREE.ShaderChunk[ "color_pars_vertex" ], - THREE.ShaderChunk[ "morphtarget_pars_vertex" ], - THREE.ShaderChunk[ "skinning_pars_vertex" ], - THREE.ShaderChunk[ "shadowmap_pars_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - THREE.ShaderChunk[ "clipping_planes_pars_vertex" ], + // put toon mapping logic right before "void main() {...}" + fragmentShader: THREE.ShaderLib[ 'phong' ].fragmentShader.replace( /void\s+main\s*\(\s*\)/, [ - // ---- MMD specific for outline drawing - " uniform bool outlineDrawing;", - " uniform float outlineThickness;", - // ---- MMD specific for outline drawing - - "void main() {", - - THREE.ShaderChunk[ "uv_vertex" ], - THREE.ShaderChunk[ "uv2_vertex" ], - THREE.ShaderChunk[ "color_vertex" ], - - THREE.ShaderChunk[ "beginnormal_vertex" ], - THREE.ShaderChunk[ "morphnormal_vertex" ], - THREE.ShaderChunk[ "skinbase_vertex" ], - THREE.ShaderChunk[ "skinnormal_vertex" ], - THREE.ShaderChunk[ "defaultnormal_vertex" ], - - "#ifndef FLAT_SHADED", // Normal computed with derivatives when FLAT_SHADED - - " vNormal = normalize( transformedNormal );", - - "#endif", - - THREE.ShaderChunk[ "begin_vertex" ], - THREE.ShaderChunk[ "displacementmap_vertex" ], - THREE.ShaderChunk[ "morphtarget_vertex" ], - THREE.ShaderChunk[ "skinning_vertex" ], - THREE.ShaderChunk[ "project_vertex" ], - THREE.ShaderChunk[ "logdepthbuf_vertex" ], - THREE.ShaderChunk[ "clipping_planes_vertex" ], - - " vViewPosition = - mvPosition.xyz;", - - THREE.ShaderChunk[ "worldpos_vertex" ], - THREE.ShaderChunk[ "envmap_vertex" ], - THREE.ShaderChunk[ "shadowmap_vertex" ], - - // ---- MMD specific for outline drawing - " if ( outlineDrawing ) {", - " float thickness = outlineThickness;", - " float ratio = 1.0;", // TODO: support outline size ratio for each vertex - " vec4 epos = projectionMatrix * modelViewMatrix * skinned;", - " vec4 epos2 = projectionMatrix * modelViewMatrix * vec4( skinned.xyz + objectNormal, 1.0 );", - " vec4 enorm = normalize( epos2 - epos );", - " gl_Position = epos + enorm * thickness * epos.w * ratio;", - " }", - // ---- MMD specific for outline drawing - - "}" - - ].join( "\n" ), - - fragmentShader: [ - - "#define PHONG", - - "uniform vec3 diffuse;", - "uniform vec3 emissive;", - "uniform vec3 specular;", - "uniform float shininess;", - "uniform float opacity;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "packing" ], - THREE.ShaderChunk[ "color_pars_fragment" ], - THREE.ShaderChunk[ "uv_pars_fragment" ], - THREE.ShaderChunk[ "uv2_pars_fragment" ], - THREE.ShaderChunk[ "map_pars_fragment" ], - THREE.ShaderChunk[ "alphamap_pars_fragment" ], - THREE.ShaderChunk[ "aomap_pars_fragment" ], - THREE.ShaderChunk[ "lightmap_pars_fragment" ], - THREE.ShaderChunk[ "emissivemap_pars_fragment" ], - THREE.ShaderChunk[ "envmap_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], - THREE.ShaderChunk[ "bsdfs" ], - THREE.ShaderChunk[ "lights_pars" ], - THREE.ShaderChunk[ "lights_phong_pars_fragment" ], - THREE.ShaderChunk[ "shadowmap_pars_fragment" ], - THREE.ShaderChunk[ "bumpmap_pars_fragment" ], - THREE.ShaderChunk[ "normalmap_pars_fragment" ], - THREE.ShaderChunk[ "specularmap_pars_fragment" ], - THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - THREE.ShaderChunk[ "clipping_planes_pars_fragment" ], - - // ---- MMD specific for cel shading - " uniform bool outlineDrawing;", - " uniform vec3 outlineColor;", - " uniform float outlineAlpha;", " uniform bool celShading;", " uniform sampler2D toonMap;", " uniform bool hasToonTexture;", @@ -3738,52 +3627,9 @@ THREE.ShaderLib[ 'mmd' ] = { "#define RE_Direct RE_Direct_BlinnMMD", // ---- MMD specific for toon mapping - "void main() {", - - // ---- MMD specific for outline drawing - " if ( outlineDrawing ) {", - " gl_FragColor = vec4( outlineColor, outlineAlpha );", - " return;", - " }", - // ---- MMD specific for outline drawing - - THREE.ShaderChunk[ "clipping_planes_fragment" ], + "void main()", - " vec4 diffuseColor = vec4( diffuse, opacity );", - " ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );", - " vec3 totalEmissiveRadiance = emissive;", - - THREE.ShaderChunk[ "logdepthbuf_fragment" ], - THREE.ShaderChunk[ "map_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], - THREE.ShaderChunk[ "alphamap_fragment" ], - THREE.ShaderChunk[ "alphatest_fragment" ], - THREE.ShaderChunk[ "specularmap_fragment" ], - THREE.ShaderChunk[ "normal_flip" ], - THREE.ShaderChunk[ "normal_fragment" ], - THREE.ShaderChunk[ "emissivemap_fragment" ], - - // accumulation - THREE.ShaderChunk[ "lights_phong_fragment" ], - THREE.ShaderChunk[ "lights_template" ], - - // modulation - THREE.ShaderChunk[ "aomap_fragment" ], - - "vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;", - - THREE.ShaderChunk[ "envmap_fragment" ], - - " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", - - THREE.ShaderChunk[ "premultiplied_alpha_fragment" ], - THREE.ShaderChunk[ "tonemapping_fragment" ], - THREE.ShaderChunk[ "encodings_fragment" ], - THREE.ShaderChunk[ "fog_fragment" ], - - "}" - - ].join( "\n" ) + ].join( "\n" ) ) }; @@ -3935,8 +3781,13 @@ THREE.MMDGrantSolver.prototype = { THREE.MMDHelper = function ( renderer ) { this.renderer = renderer; + + this.outlineEffect = null; + this.effect = null; + this.autoClear = true; + this.meshes = []; this.doAnimation = true; @@ -3959,15 +3810,10 @@ THREE.MMDHelper.prototype = { init: function () { - this.initRender(); - - }, + this.outlineEffect = new THREE.OutlineEffect( this.renderer ); - initRender: function () { - - this.renderer.autoClear = false; - this.renderer.autoClearColor = false; - this.renderer.autoClearDepth = false; + var size = this.renderer.getSize(); + this.setSize( size.width, size.height ); }, @@ -3990,6 +3836,12 @@ THREE.MMDHelper.prototype = { }, + setSize: function ( width, height ) { + + this.outlineEffect.setSize( width, height ); + + }, + /* * Note: There may be a possibility that Outline wouldn't work well with Effect. * In such a case, try to set doOutlineDrawing = false or @@ -4106,7 +3958,7 @@ THREE.MMDHelper.prototype = { }, /* - * detect the longest duration among model, camera, and audio animation and then + * detect the longest duration among model, camera, and audio animations and then * set it to them to sync. * TODO: touching private properties ( ._actions and ._clip ) so consider better way * to access them for safe and modularity. @@ -4298,187 +4150,135 @@ THREE.MMDHelper.prototype = { render: function ( scene, camera ) { - this.renderer.clearColor(); - this.renderer.clearDepth(); - this.renderer.clear( true, true ); - - this.renderMain( scene, camera ); - - if ( this.doOutlineDrawing ) { - - this.renderOutline( scene, camera ); - - } - - }, - - renderMain: function ( scene, camera ) { - - this.setupMainRendering(); - this.callRender( scene, camera ); - - }, - - renderOutline: function () { - - var invisibledObjects = []; - var setInvisible; - var restoreVisible; - - return function renderOutline( scene, camera ) { + if ( this.effect === null ) { - var self = this; + if ( this.doOutlineDrawing ) { - if ( setInvisible === undefined ) { + this.outlineEffect.autoClear = this.autoClear; + this.outlineEffect.render( scene, camera ); - setInvisible = function ( object ) { + } else { - if ( ! object.visible || ! object.layers.test( camera.layers ) ) return; + var currentAutoClear = this.renderer.autoClear; + this.renderer.autoClear = this.autoClear; + this.renderer.render( scene, camera ); + this.renderer.autoClear = currentAutoClear; - // any types else to skip? - if ( object instanceof THREE.Scene || - object instanceof THREE.Bone || - object instanceof THREE.Light || - object instanceof THREE.Camera || - object instanceof THREE.Audio || - object instanceof THREE.AudioListener ) return; + } - if ( object instanceof THREE.SkinnedMesh ) { + } else { - for ( var i = 0, il = self.meshes.length; i < il; i ++ ) { + var currentAutoClear = this.renderer.autoClear; + this.renderer.autoClear = this.autoClear; - if ( self.meshes[ i ] === object ) return; + if ( this.doOutlineDrawing ) { - } + this.renderWithEffectAndOutline( scene, camera ); - } + } else { - object.layers.mask &= ~ camera.layers.mask; - invisibledObjects.push( object ); - - }; + this.effect.render( scene, camera ); } - if ( restoreVisible === undefined ) { - - restoreVisible = function () { - - for ( var i = 0, il = invisibledObjects.length; i < il; i ++ ) { - - invisibledObjects[ i ].layers.mask |= camera.layers.mask; - - } - - invisibledObjects.length = 0; + this.renderer.autoClear = currentAutoClear; - }; - - } + } - scene.traverse( setInvisible ); + }, - var tmpEnabled = this.renderer.shadowMap.enabled; - this.renderer.shadowMap.enabled = false; + /* + * Currently(r82 dev) there's no way to render with two Effects + * then attempt to get them to coordinately run by myself. + * + * What this method does + * 1. let OutlineEffect make outline materials (only once) + * 2. render normally with effect + * 3. set outline materials + * 4. render outline with effect + * 5. restore original materials + */ + renderWithEffectAndOutline: function ( scene, camera ) { - this.setupOutlineRendering(); - this.callRender( scene, camera ); + var hasOutlineMaterial = false; - this.renderer.shadowMap.enabled = tmpEnabled; + function checkIfObjectHasOutlineMaterial ( object ) { - restoreVisible(); + if ( object.material === undefined ) return; - }; + if ( object.userData.outlineMaterial !== undefined ) hasOutlineMaterial = true; - }(), + } - callRender: function ( scene, camera ) { + function setOutlineMaterial ( object ) { - if ( this.effect === null ) { + if ( object.material === undefined ) return; - this.renderer.render( scene, camera ); + if ( object.userData.outlineMaterial === undefined ) return; - } else { + object.userData.originalMaterial = object.material; - this.effect.render( scene, camera ); + object.material = object.userData.outlineMaterial; } - }, + function restoreOriginalMaterial ( object ) { - setupMainRendering: function () { + if ( object.material === undefined ) return; - for ( var i = 0; i < this.meshes.length; i++ ) { + if ( object.userData.originalMaterial === undefined ) return; - this.setupMainRenderingOneMesh( this.meshes[ i ] ); + object.material = object.userData.originalMaterial; } - }, + return function renderWithEffectAndOutline( scene, camera ) { - setupMainRenderingOneMesh: function ( mesh ) { + hasOutlineMaterial = false; - for ( var i = 0; i < mesh.material.materials.length; i++ ) { + var forceClear = false; - var m = mesh.material.materials[ i ]; - m.uniforms.outlineDrawing.value = 0; - m.visible = true; + scene.traverse( checkIfObjectHasOutlineMaterial ); - if ( m.uniforms.opacity.value === 1.0 ) { + if ( ! hasOutlineMaterial ) { - m.side = THREE.FrontSide; - m.transparent = false; + this.outlineEffect.render( scene, camera ); - } else { + forceClear = true; - m.side = THREE.DoubleSide; - m.transparent = true; + scene.traverse( checkIfObjectHasOutlineMaterial ); } - if ( m.textureTransparency === true || m.morphTransparency === true ) { + if ( hasOutlineMaterial ) { - m.transparent = true; + this.renderer.autoClear = this.autoClear || forceClear; - } + this.effect.render( scene, camera ); - } + scene.traverse( setOutlineMaterial ); - }, + var currentShadowMapEnabled = this.renderer.shadowMap.enabled; - setupOutlineRendering: function () { + this.renderer.autoClear = false; + this.renderer.shadowMap.enabled = false; - for ( var i = 0; i < this.meshes.length; i++ ) { + this.effect.render( scene, camera ); - this.setupOutlineRenderingOneMesh( this.meshes[ i ] ); + this.renderer.shadowMap.enabled = currentShadowMapEnabled; - } - - }, - - setupOutlineRenderingOneMesh: function ( mesh ) { - - for ( var i = 0; i < mesh.material.materials.length; i++ ) { - - var m = mesh.material.materials[ i ]; - m.uniforms.outlineDrawing.value = 1; - m.side = THREE.BackSide; - - if ( m.uniforms.outlineAlpha.value < 1.0 ) { + scene.traverse( restoreOriginalMaterial ); - m.transparent = true; - - } - - if ( m.uniforms.outlineThickness.value === 0.0 ) { + } else { - m.visible = false; + this.outlineEffect.autoClear = this.autoClear || forceClear; + this.outlineEffect.render( scene, camera ); } } - }, + }(), poseAsVpd: function ( mesh, vpd, params ) { diff --git a/examples/webgl_loader_mmd.html b/examples/webgl_loader_mmd.html index e9e5c68b7a0730858ee223be60c09509f2ec34c0..07cdd717e2c27d2a42c30664d93be5a0b7f9c60e 100644 --- a/examples/webgl_loader_mmd.html +++ b/examples/webgl_loader_mmd.html @@ -37,8 +37,10 @@ + + @@ -151,7 +153,7 @@ camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); - renderer.setSize( window.innerWidth, window.innerHeight ); + helper.setSize( window.innerWidth, window.innerHeight ); } @@ -185,7 +187,6 @@ } else { - renderer.clear(); renderer.render( scene, camera ); } diff --git a/examples/webgl_loader_mmd_audio.html b/examples/webgl_loader_mmd_audio.html index 4ce080b41771cd4e90cded7824cd4be9a7329792..3c2f93ae21c336f7e869d2b5f2278465bab0daa0 100644 --- a/examples/webgl_loader_mmd_audio.html +++ b/examples/webgl_loader_mmd_audio.html @@ -40,8 +40,10 @@ + + @@ -188,7 +190,7 @@ camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); - renderer.setSize( window.innerWidth, window.innerHeight ); + helper.setSize( window.innerWidth, window.innerHeight ); } @@ -218,7 +220,6 @@ } else { - renderer.clear(); renderer.render( scene, camera ); } diff --git a/examples/webgl_loader_mmd_pose.html b/examples/webgl_loader_mmd_pose.html index f738d5b707bc20fea843ba55a1d147bc89a01549..653ef2e0dec74d05a74e2dd371ad7ad7505ced4d 100644 --- a/examples/webgl_loader_mmd_pose.html +++ b/examples/webgl_loader_mmd_pose.html @@ -37,8 +37,10 @@ + + @@ -293,7 +295,7 @@ camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); - renderer.setSize( window.innerWidth, window.innerHeight ); + helper.setSize( window.innerWidth, window.innerHeight ); } @@ -326,7 +328,6 @@ } else { - renderer.clear(); renderer.render( scene, camera ); }