"use strict"; THREE.FlexMaterial = function(spec){ const _worldMatrixDelayed = new THREE['Matrix4'](); function mix(a,b,t){ a.set( b.x*t+a.x*(1-t), b.y*t+a.y*(1-t), b.z*t+a.z*(1-t) ); } // tweak shaders helpers: function tweak_shaderAdd(code, chunk, glslCode){ return code.replace(chunk, chunk+"\n"+glslCode); } function tweak_shaderDel(code, chunk){ return code.replace(chunk, ''); } function tweak_shaderRepl(code, chunk, glslCode){ return code.replace(chunk, glslCode); } // get PHONG shader and tweak it : const phongShader = THREE.ShaderLib.phong; let vertexShaderSource = phongShader.vertexShader; vertexShaderSource = tweak_shaderAdd(vertexShaderSource, '#include ', 'uniform mat4 modelMatrixDelayed;\n' +'uniform sampler2D flexMap;\n' ); vertexShaderSource = tweak_shaderDel(vertexShaderSource, '#include '); vertexShaderSource = tweak_shaderRepl(vertexShaderSource, '#include ', "vec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\n\ vec4 worldPositionDelayed = modelMatrixDelayed * vec4( transformed, 1.0 );\n\ worldPosition = mix(worldPosition, worldPositionDelayed, texture2D(flexMap, uv).r);\n\ vec4 mvPosition = viewMatrix* worldPosition;\n\ gl_Position = projectionMatrix * mvPosition;"); const uniforms0 = { 'modelMatrixDelayed': { 'value': _worldMatrixDelayed }, 'flexMap': { value: spec.flexMap }, 'opacity': { value: (typeof(spec.opacity)!=='undefined')?spec.opacity:1 } }; const uniforms = Object.assign({}, phongShader.uniforms, uniforms0); const isMorphs = (spec.morphTargets) ? true : false; const mat = new THREE.ShaderMaterial({ vertexShader: vertexShaderSource, fragmentShader: phongShader.fragmentShader, uniforms: uniforms, transparent: (spec.transparent)?true:false, lights: true, morphTargets: isMorphs, morphNormals: isMorphs }); mat.flexMap = spec.flexMap; mat.opacity = mat.uniforms.opacity; // shortcut if (typeof(spec.map)!=='undefined') { uniforms.map = {value: spec.map}; mat.map = spec.map; } if (typeof(spec.alphaMap)!=='undefined') { uniforms.alphaMap = {value: spec.alphaMap}; mat.transparent = true; mat.alphaMap = spec.alphaMap; } if (typeof(spec.bumpMap)!=='undefined') { uniforms.bumpMap = {value: spec.bumpMap}; mat.bumpMap = spec.bumpMap; } if (typeof(spec.bumpScale)!=='undefined') { uniforms.bumpScale = {value: spec.bumpScale}; mat.bumpScale = spec.bumpScale; } if (typeof(spec.shininess)!=='undefined') { uniforms.shininess = {value: spec.shininess}; mat.shininess = spec.shininess; } const _positionDelayed = new THREE.Vector3(); const _scaleDelayed = new THREE.Vector3(); const _eulerDelayed = new THREE['Euler'](); let _initialized = false; mat.set_amortized = function(positionTarget, scaleTarget, eulerTarget, parentMatrix, amortization){ if (!_initialized){ if (positionTarget){ _positionDelayed.copy(positionTarget); } if (scaleTarget){ _scaleDelayed.copy(scaleTarget); } if (eulerTarget){ _eulerDelayed.copy(eulerTarget); } _initialized = true; } if (eulerTarget){ mix( _eulerDelayed, eulerTarget, amortization ); _worldMatrixDelayed['makeRotationFromEuler'](_eulerDelayed); } if (positionTarget){ mix( _positionDelayed, positionTarget, amortization ); _worldMatrixDelayed['setPosition'](_positionDelayed); } if (scaleTarget){ mix(_scaleDelayed, scaleTarget, amortization ); _worldMatrixDelayed['scale'](_scaleDelayed); } if (parentMatrix){ _worldMatrixDelayed.multiplyMatrices(parentMatrix, _worldMatrixDelayed); } } return mat; };