diff --git a/stitchcode/threee/CanvasRenderer.js b/stitchcode/threee/CanvasRenderer.js index 6b128053..95ef9550 100644 --- a/stitchcode/threee/CanvasRenderer.js +++ b/stitchcode/threee/CanvasRenderer.js @@ -9,7 +9,7 @@ THREE.SpriteCanvasMaterial = function ( parameters ) { this.type = 'SpriteCanvasMaterial'; this.color = new THREE.Color( 0xffffff ); - this.program = function ( context, color ) {}; + this.program = function () {}; this.setValues( parameters ); @@ -17,6 +17,7 @@ THREE.SpriteCanvasMaterial = function ( parameters ) { THREE.SpriteCanvasMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.SpriteCanvasMaterial.prototype.constructor = THREE.SpriteCanvasMaterial; +THREE.SpriteCanvasMaterial.prototype.isSpriteCanvasMaterial = true; THREE.SpriteCanvasMaterial.prototype.clone = function () { @@ -39,78 +40,69 @@ THREE.CanvasRenderer = function ( parameters ) { parameters = parameters || {}; var _this = this, - _renderData, _elements, _lights, - _projector = new THREE.Projector(), + _renderData, _elements, _lights, + _projector = new THREE.Projector(), - _canvas = parameters.canvas !== undefined - ? parameters.canvas - : document.createElement( 'canvas' ), + _canvas = parameters.canvas !== undefined + ? parameters.canvas + : document.createElement( 'canvas' ), - _canvasWidth = _canvas.width, - _canvasHeight = _canvas.height, - _canvasWidthHalf = Math.floor( _canvasWidth / 2 ), - _canvasHeightHalf = Math.floor( _canvasHeight / 2 ), + _canvasWidth = _canvas.width, + _canvasHeight = _canvas.height, + _canvasWidthHalf = Math.floor( _canvasWidth / 2 ), + _canvasHeightHalf = Math.floor( _canvasHeight / 2 ), - _viewportX = 0, - _viewportY = 0, - _viewportWidth = _canvasWidth, - _viewportHeight = _canvasHeight, + _viewportX = 0, + _viewportY = 0, + _viewportWidth = _canvasWidth, + _viewportHeight = _canvasHeight, - _pixelRatio = 1, + _pixelRatio = 1, - _context = _canvas.getContext( '2d', { - alpha: parameters.alpha === true - } ), + _context = _canvas.getContext( '2d', { + alpha: parameters.alpha === true + } ), - _clearColor = new THREE.Color( 0x000000 ), - _clearAlpha = parameters.alpha === true ? 0 : 1, + _clearColor = new THREE.Color( 0x000000 ), + _clearAlpha = parameters.alpha === true ? 0 : 1, - _contextGlobalAlpha = 1, - _contextGlobalCompositeOperation = 0, - _contextStrokeStyle = null, - _contextFillStyle = null, - _contextLineWidth = null, - _contextLineCap = null, - _contextLineJoin = null, - _contextLineDash = [], + _contextGlobalAlpha = 1, + _contextGlobalCompositeOperation = 0, + _contextStrokeStyle = null, + _contextFillStyle = null, + _contextLineWidth = null, + _contextLineCap = null, + _contextLineJoin = null, + _contextLineDash = [], - _camera, + _v1, _v2, _v3, - _v1, _v2, _v3, _v4, - _v5 = new THREE.RenderableVertex(), - _v6 = new THREE.RenderableVertex(), + _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, - _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, - _v4x, _v4y, _v5x, _v5y, _v6x, _v6y, + _color = new THREE.Color(), - _color = new THREE.Color(), - _color1 = new THREE.Color(), - _color2 = new THREE.Color(), - _color3 = new THREE.Color(), - _color4 = new THREE.Color(), + _diffuseColor = new THREE.Color(), + _emissiveColor = new THREE.Color(), - _diffuseColor = new THREE.Color(), - _emissiveColor = new THREE.Color(), + _lightColor = new THREE.Color(), - _lightColor = new THREE.Color(), + _patterns = {}, - _patterns = {}, + _uvs, + _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, - _image, _uvs, - _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, + _clipBox = new THREE.Box2(), + _clearBox = new THREE.Box2(), + _elemBox = new THREE.Box2(), - _clipBox = new THREE.Box2(), - _clearBox = new THREE.Box2(), - _elemBox = new THREE.Box2(), + _ambientLight = new THREE.Color(), + _directionalLights = new THREE.Color(), + _pointLights = new THREE.Color(), - _ambientLight = new THREE.Color(), - _directionalLights = new THREE.Color(), - _pointLights = new THREE.Color(), - - _vector3 = new THREE.Vector3(), // Needed for PointLight - _centroid = new THREE.Vector3(), - _normal = new THREE.Vector3(), - _normalViewMatrix = new THREE.Matrix3(); + _vector3 = new THREE.Vector3(), // Needed for PointLight + _centroid = new THREE.Vector3(), + _normal = new THREE.Vector3(), + _normalViewMatrix = new THREE.Matrix3(); /* TODO _canvas.mozImageSmoothingEnabled = false; @@ -266,10 +258,10 @@ THREE.CanvasRenderer = function ( parameters ) { _clearBox.intersect( _clipBox ); _clearBox.expandByScalar( 2 ); - _clearBox.min.x = _clearBox.min.x + _canvasWidthHalf; - _clearBox.min.y = - _clearBox.min.y + _canvasHeightHalf; // higher y value ! - _clearBox.max.x = _clearBox.max.x + _canvasWidthHalf; - _clearBox.max.y = - _clearBox.max.y + _canvasHeightHalf; // lower y value ! + _clearBox.min.x = _clearBox.min.x + _canvasWidthHalf; + _clearBox.min.y = - _clearBox.min.y + _canvasHeightHalf; // higher y value ! + _clearBox.max.x = _clearBox.max.x + _canvasWidthHalf; + _clearBox.max.y = - _clearBox.max.y + _canvasHeightHalf; // lower y value ! if ( _clearAlpha < 1 ) { @@ -312,7 +304,7 @@ THREE.CanvasRenderer = function ( parameters ) { this.render = function ( scene, camera ) { - if ( camera instanceof THREE.Camera === false ) { + if ( camera.isCamera === undefined ) { console.error( 'THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.' ); return; @@ -341,7 +333,6 @@ THREE.CanvasRenderer = function ( parameters ) { _renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements ); _elements = _renderData.elements; _lights = _renderData.lights; - _camera = camera; _normalViewMatrix.getNormalMatrix( camera.matrixWorldInverse ); @@ -454,17 +445,17 @@ THREE.CanvasRenderer = function ( parameters ) { var light = _lights[ l ]; var lightColor = light.color; - if ( light instanceof THREE.AmbientLight ) { + if ( light.isAmbientLight ) { _ambientLight.add( lightColor ); - } else if ( light instanceof THREE.DirectionalLight ) { + } else if ( light.isDirectionalLight ) { // for sprites _directionalLights.add( lightColor ); - } else if ( light instanceof THREE.PointLight ) { + } else if ( light.isPointLight ) { // for sprites @@ -484,7 +475,7 @@ THREE.CanvasRenderer = function ( parameters ) { _lightColor.copy( light.color ); - if ( light instanceof THREE.DirectionalLight ) { + if ( light.isDirectionalLight ) { var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ).normalize(); @@ -496,7 +487,7 @@ THREE.CanvasRenderer = function ( parameters ) { color.add( _lightColor.multiplyScalar( amount ) ); - } else if ( light instanceof THREE.PointLight ) { + } else if ( light.isPointLight ) { var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ); @@ -526,11 +517,11 @@ THREE.CanvasRenderer = function ( parameters ) { var scaleX = element.scale.x * _canvasWidthHalf; var scaleY = element.scale.y * _canvasHeightHalf; - var dist = 0.5 * Math.sqrt( scaleX * scaleX + scaleY * scaleY ); // allow for rotated sprite + var dist = Math.sqrt( scaleX * scaleX + scaleY * scaleY ); // allow for rotated sprite _elemBox.min.set( v1.x - dist, v1.y - dist ); _elemBox.max.set( v1.x + dist, v1.y + dist ); - if ( material instanceof THREE.SpriteMaterial ) { + if ( material.isSpriteMaterial ) { var texture = material.map; @@ -586,7 +577,7 @@ THREE.CanvasRenderer = function ( parameters ) { } - } else if ( material instanceof THREE.SpriteCanvasMaterial ) { + } else if ( material.isSpriteCanvasMaterial ) { setStrokeStyle( material.color.getStyle() ); setFillStyle( material.color.getStyle() ); @@ -600,6 +591,17 @@ THREE.CanvasRenderer = function ( parameters ) { _context.restore(); + } else if ( material.isPointsMaterial ) { + + setFillStyle( material.color.getStyle() ); + + _context.save(); + _context.translate( v1.x, v1.y ); + if ( material.rotation !== 0 ) _context.rotate( material.rotation ); + _context.scale( scaleX * material.size, - scaleY * material.size ); + _context.fillRect( - 0.5, - 0.5, 1, 1 ); + _context.restore(); + } /* DEBUG @@ -623,7 +625,7 @@ THREE.CanvasRenderer = function ( parameters ) { _context.moveTo( v1.positionScreen.x, v1.positionScreen.y ); _context.lineTo( v2.positionScreen.x, v2.positionScreen.y ); - if ( material instanceof THREE.LineBasicMaterial ) { + if ( material.isLineBasicMaterial ) { setLineWidth( material.linewidth ); setLineCap( material.linecap ); @@ -670,7 +672,7 @@ THREE.CanvasRenderer = function ( parameters ) { _context.stroke(); _elemBox.expandByScalar( material.linewidth * 2 ); - } else if ( material instanceof THREE.LineDashedMaterial ) { + } else if ( material.isLineDashedMaterial ) { setLineWidth( material.linewidth ); setLineCap( material.linecap ); @@ -702,7 +704,7 @@ THREE.CanvasRenderer = function ( parameters ) { drawTriangle( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y ); - if ( ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) && material.map === null ) { + if ( ( material.isMeshLambertMaterial || material.isMeshPhongMaterial || material.isMeshStandardMaterial ) && material.map === null ) { _diffuseColor.copy( material.color ); _emissiveColor.copy( material.emissive ); @@ -725,9 +727,7 @@ THREE.CanvasRenderer = function ( parameters ) { ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) : fillPath( _color ); - } else if ( material instanceof THREE.MeshBasicMaterial || - material instanceof THREE.MeshLambertMaterial || - material instanceof THREE.MeshPhongMaterial ) { + } else if ( material.isMeshBasicMaterial || material.isMeshLambertMaterial || material.isMeshPhongMaterial || material.isMeshStandardMaterial ) { if ( material.map !== null ) { @@ -776,7 +776,7 @@ THREE.CanvasRenderer = function ( parameters ) { } - } else if ( material instanceof THREE.MeshNormalMaterial ) { + } else if ( material.isMeshNormalMaterial ) { _normal.copy( element.normalModel ).applyMatrix3( _normalViewMatrix ); @@ -944,10 +944,10 @@ THREE.CanvasRenderer = function ( parameters ) { // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 var a, b, c, d, e, f, det, idet, - offsetX = texture.offset.x / texture.repeat.x, - offsetY = texture.offset.y / texture.repeat.y, - width = texture.image.width * texture.repeat.x, - height = texture.image.height * texture.repeat.y; + offsetX = texture.offset.x / texture.repeat.x, + offsetY = texture.offset.y / texture.repeat.y, + width = texture.image.width * texture.repeat.x, + height = texture.image.height * texture.repeat.y; u0 = ( u0 + offsetX ) * width; v0 = ( v0 + offsetY ) * height; @@ -985,6 +985,7 @@ THREE.CanvasRenderer = function ( parameters ) { } + /* function clipImage( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, image ) { // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 @@ -1022,13 +1023,14 @@ THREE.CanvasRenderer = function ( parameters ) { _context.restore(); } + */ // Hide anti-alias gaps function expand( v1, v2, pixels ) { var x = v2.x - v1.x, y = v2.y - v1.y, - det = x * x + y * y, idet; + det = x * x + y * y, idet; if ( det === 0 ) return; diff --git a/stitchcode/threee/OBJLoader.js b/stitchcode/threee/OBJLoader.js index c11b68b6..6556a4d4 100644 --- a/stitchcode/threee/OBJLoader.js +++ b/stitchcode/threee/OBJLoader.js @@ -720,8 +720,7 @@ THREE.OBJLoader.prototype = { } - var multiMaterial = new THREE.MultiMaterial( createdMaterials ); - mesh = ( ! isLine ? new THREE.Mesh( buffergeometry, multiMaterial ) : new THREE.LineSegments( buffergeometry, multiMaterial ) ); + mesh = ( ! isLine ? new THREE.Mesh( buffergeometry, createdMaterials ) : new THREE.LineSegments( buffergeometry, createdMaterials ) ); } else { diff --git a/stitchcode/threee/OrbitControls.js b/stitchcode/threee/OrbitControls.js index ed3b5e9f..bf662dd7 100644 --- a/stitchcode/threee/OrbitControls.js +++ b/stitchcode/threee/OrbitControls.js @@ -5,78 +5,260 @@ * @author WestLangley / http://github.com/WestLangley * @author erich666 / http://erichaines.com */ -/*global THREE, console */ -// This set of controls performs orbiting, dollying (zooming), and panning. It maintains -// the "up" direction as +Y, unlike the TrackballControls. Touch on tablet and phones is -// supported. +// This set of controls performs orbiting, dollying (zooming), and panning. +// Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default). // // Orbit - left mouse / touch: one finger move // Zoom - middle mouse, or mousewheel / touch: two finger spread or squish -// Pan - right mouse, or arrow keys / touch: three finter swipe -// -// This is a drop-in replacement for (most) TrackballControls used in examples. -// That is, include this js file and wherever you see: -// controls = new THREE.TrackballControls( camera ); -// controls.target.z = 150; -// Simple substitute "OrbitControls" and the control should work as-is. +// Pan - right mouse, or arrow keys / touch: three finger swipe THREE.OrbitControls = function ( object, domElement ) { this.object = object; - this.domElement = ( domElement !== undefined ) ? domElement : document; - // API + this.domElement = ( domElement !== undefined ) ? domElement : document; // Set to false to disable this control this.enabled = true; - // "target" sets the location of focus, where the control orbits around - // and where it pans with respect to. + // "target" sets the location of focus, where the object orbits around this.target = new THREE.Vector3(); - // center is old, deprecated; use "target" instead - this.center = this.target; - - // This option actually enables dollying in and out; left as "zoom" for - // backwards compatibility - this.noZoom = false; - this.zoomSpeed = 1.0; - - // Limits to how far you can dolly in and out + // How far you can dolly in and out ( PerspectiveCamera only ) this.minDistance = 0; this.maxDistance = Infinity; - // Set to true to disable this control - this.noRotate = false; - this.rotateSpeed = 1.0; - - // Set to true to disable this control - this.noPan = false; - this.keyPanSpeed = 7.0; // pixels moved per arrow key push - - // Set to true to automatically rotate around the target - this.autoRotate = false; - this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 + // How far you can zoom in and out ( OrthographicCamera only ) + this.minZoom = 0; + this.maxZoom = Infinity; // How far you can orbit vertically, upper and lower limits. // Range is 0 to Math.PI radians. this.minPolarAngle = 0; // radians this.maxPolarAngle = Math.PI; // radians - // Set to true to disable use of the keys - this.noKeys = true; + // How far you can orbit horizontally, upper and lower limits. + // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ]. + this.minAzimuthAngle = - Infinity; // radians + this.maxAzimuthAngle = Infinity; // radians + + // Set to true to enable damping (inertia) + // If damping is enabled, you must call controls.update() in your animation loop + this.enableDamping = false; + this.dampingFactor = 0.25; + + // This option actually enables dollying in and out; left as "zoom" for backwards compatibility. + // Set to false to disable zooming + this.enableZoom = true; + this.zoomSpeed = 1.0; + + // Set to false to disable rotating + this.enableRotate = true; + this.rotateSpeed = 1.0; + + // Set to false to disable panning + this.enablePan = true; + this.keyPanSpeed = 7.0; // pixels moved per arrow key push + + // Set to true to automatically rotate around the target + // If auto-rotate is enabled, you must call controls.update() in your animation loop + this.autoRotate = false; + this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 + + // Set to false to disable use of the keys + this.enableKeys = true; // The four arrow keys this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 }; - //////////// + // Mouse buttons + this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT }; + + // for reset + this.target0 = this.target.clone(); + this.position0 = this.object.position.clone(); + this.zoom0 = this.object.zoom; + + // + // public methods + // + + this.getPolarAngle = function () { + + return spherical.phi; + + }; + + this.getAzimuthalAngle = function () { + + return spherical.theta; + + }; + + this.saveState = function () { + + scope.target0.copy( scope.target ); + scope.position0.copy( scope.object.position ); + scope.zoom0 = scope.object.zoom; + + }; + + this.reset = function () { + + scope.target.copy( scope.target0 ); + scope.object.position.copy( scope.position0 ); + scope.object.zoom = scope.zoom0; + + scope.object.updateProjectionMatrix(); + scope.dispatchEvent( changeEvent ); + + scope.update(); + + state = STATE.NONE; + + }; + + // this method is exposed, but perhaps it would be better if we can make it private... + this.update = function () { + + var offset = new THREE.Vector3(); + + // so camera.up is the orbit axis + var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) ); + var quatInverse = quat.clone().inverse(); + + var lastPosition = new THREE.Vector3(); + var lastQuaternion = new THREE.Quaternion(); + + return function update() { + + var position = scope.object.position; + + offset.copy( position ).sub( scope.target ); + + // rotate offset to "y-axis-is-up" space + offset.applyQuaternion( quat ); + + // angle from z-axis around y-axis + spherical.setFromVector3( offset ); + + if ( scope.autoRotate && state === STATE.NONE ) { + + rotateLeft( getAutoRotationAngle() ); + + } + + spherical.theta += sphericalDelta.theta; + spherical.phi += sphericalDelta.phi; + + // restrict theta to be between desired limits + spherical.theta = Math.max( scope.minAzimuthAngle, Math.min( scope.maxAzimuthAngle, spherical.theta ) ); + + // restrict phi to be between desired limits + spherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) ); + + spherical.makeSafe(); + + + spherical.radius *= scale; + + // restrict radius to be between desired limits + spherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) ); + + // move target to panned location + scope.target.add( panOffset ); + + offset.setFromSpherical( spherical ); + + // rotate offset back to "camera-up-vector-is-up" space + offset.applyQuaternion( quatInverse ); + + position.copy( scope.target ).add( offset ); + + scope.object.lookAt( scope.target ); + + if ( scope.enableDamping === true ) { + + sphericalDelta.theta *= ( 1 - scope.dampingFactor ); + sphericalDelta.phi *= ( 1 - scope.dampingFactor ); + + } else { + + sphericalDelta.set( 0, 0, 0 ); + + } + + scale = 1; + panOffset.set( 0, 0, 0 ); + + // update condition is: + // min(camera displacement, camera rotation in radians)^2 > EPS + // using small-angle approximation cos(x/2) = 1 - x^2 / 8 + + if ( zoomChanged || + lastPosition.distanceToSquared( scope.object.position ) > EPS || + 8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) { + + scope.dispatchEvent( changeEvent ); + + lastPosition.copy( scope.object.position ); + lastQuaternion.copy( scope.object.quaternion ); + zoomChanged = false; + + return true; + + } + + return false; + + }; + + }(); + + this.dispose = function () { + + scope.domElement.removeEventListener( 'contextmenu', onContextMenu, false ); + scope.domElement.removeEventListener( 'mousedown', onMouseDown, false ); + scope.domElement.removeEventListener( 'wheel', onMouseWheel, false ); + + scope.domElement.removeEventListener( 'touchstart', onTouchStart, false ); + scope.domElement.removeEventListener( 'touchend', onTouchEnd, false ); + scope.domElement.removeEventListener( 'touchmove', onTouchMove, false ); + + document.removeEventListener( 'mousemove', onMouseMove, false ); + document.removeEventListener( 'mouseup', onMouseUp, false ); + + window.removeEventListener( 'keydown', onKeyDown, false ); + + //scope.dispatchEvent( { type: 'dispose' } ); // should this be added here? + + }; + + // // internals + // var scope = this; + var changeEvent = { type: 'change' }; + var startEvent = { type: 'start' }; + var endEvent = { type: 'end' }; + + var STATE = { NONE: - 1, ROTATE: 0, DOLLY: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_DOLLY: 4, TOUCH_PAN: 5 }; + + var state = STATE.NONE; + var EPS = 0.000001; + // current position in spherical coordinates + var spherical = new THREE.Spherical(); + var sphericalDelta = new THREE.Spherical(); + + var scale = 1; + var panOffset = new THREE.Vector3(); + var zoomChanged = false; + var rotateStart = new THREE.Vector2(); var rotateEnd = new THREE.Vector2(); var rotateDelta = new THREE.Vector2(); @@ -84,217 +266,11 @@ THREE.OrbitControls = function ( object, domElement ) { var panStart = new THREE.Vector2(); var panEnd = new THREE.Vector2(); var panDelta = new THREE.Vector2(); - var panOffset = new THREE.Vector3(); - - var offset = new THREE.Vector3(); var dollyStart = new THREE.Vector2(); var dollyEnd = new THREE.Vector2(); var dollyDelta = new THREE.Vector2(); - var phiDelta = 0; - var thetaDelta = 0; - var scale = 1; - var pan = new THREE.Vector3(); - - var lastPosition = new THREE.Vector3(); - - var STATE = { NONE : -1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 }; - - var state = STATE.NONE; - - // for reset - - this.target0 = this.target.clone(); - this.position0 = this.object.position.clone(); - - // events - - var changeEvent = { type: 'change' }; - var startEvent = { type: 'start'}; - var endEvent = { type: 'end'}; - - this.rotateLeft = function ( angle ) { - - if ( angle === undefined ) { - - angle = getAutoRotationAngle(); - - } - - thetaDelta -= angle; - - }; - - this.rotateUp = function ( angle ) { - - if ( angle === undefined ) { - - angle = getAutoRotationAngle(); - - } - - phiDelta -= angle; - - }; - - // pass in distance in world space to move left - this.panLeft = function ( distance ) { - - var te = this.object.matrix.elements; - - // get X column of matrix - panOffset.set( te[ 0 ], te[ 1 ], te[ 2 ] ); - panOffset.multiplyScalar( - distance ); - - pan.add( panOffset ); - - }; - - // pass in distance in world space to move up - this.panUp = function ( distance ) { - - var te = this.object.matrix.elements; - - // get Y column of matrix - panOffset.set( te[ 4 ], te[ 5 ], te[ 6 ] ); - panOffset.multiplyScalar( distance ); - - pan.add( panOffset ); - - }; - - // pass in x,y of change desired in pixel space, - // right and down are positive - this.pan = function ( deltaX, deltaY ) { - - var element = scope.domElement === document ? scope.domElement.body : scope.domElement; - - if ( scope.object.fov !== undefined ) { - - // perspective - var position = scope.object.position; - var offset = position.clone().sub( scope.target ); - var targetDistance = offset.length(); - - // half of the fov is center to top of screen - targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 ); - - // we actually don't use screenWidth, since perspective camera is fixed to screen height - scope.panLeft( 2 * deltaX * targetDistance / element.clientHeight ); - scope.panUp( 2 * deltaY * targetDistance / element.clientHeight ); - - } else if ( scope.object.top !== undefined ) { - - // orthographic - scope.panLeft( deltaX * (scope.object.right - scope.object.left) / element.clientWidth ); - scope.panUp( deltaY * (scope.object.top - scope.object.bottom) / element.clientHeight ); - - } else { - - // camera neither orthographic or perspective - console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' ); - - } - - }; - - this.dollyIn = function ( dollyScale ) { - - if ( dollyScale === undefined ) { - - dollyScale = getZoomScale(); - - } - - scale /= dollyScale; - - }; - - this.dollyOut = function ( dollyScale ) { - - if ( dollyScale === undefined ) { - - dollyScale = getZoomScale(); - - } - - scale *= dollyScale; - - }; - - this.update = function () { - - var position = this.object.position; - - offset.copy( position ).sub( this.target ); - - // angle from z-axis around y-axis - - var theta = Math.atan2( offset.x, offset.z ); - - // angle from y-axis - - var phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y ); - - if ( this.autoRotate ) { - - this.rotateLeft( getAutoRotationAngle() ); - - } - - theta += thetaDelta; - phi += phiDelta; - - // restrict phi to be between desired limits - phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) ); - - // restrict phi to be betwee EPS and PI-EPS - phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) ); - - var radius = offset.length() * scale; - - // restrict radius to be between desired limits - radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) ); - - // move target to panned location - this.target.add( pan ); - - offset.x = radius * Math.sin( phi ) * Math.sin( theta ); - offset.y = radius * Math.cos( phi ); - offset.z = radius * Math.sin( phi ) * Math.cos( theta ); - - position.copy( this.target ).add( offset ); - - this.object.lookAt( this.target ); - - thetaDelta = 0; - phiDelta = 0; - scale = 1; - pan.set( 0, 0, 0 ); - - if ( lastPosition.distanceTo( this.object.position ) > 0 ) { - - this.dispatchEvent( changeEvent ); - - lastPosition.copy( this.object.position ); - - } - - }; - - - this.reset = function () { - - state = STATE.NONE; - - this.target.copy( this.target0 ); - this.object.position.copy( this.position0 ); - - this.update(); - - }; - function getAutoRotationAngle() { return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; @@ -307,37 +283,427 @@ THREE.OrbitControls = function ( object, domElement ) { } - function onMouseDown( event ) { + function rotateLeft( angle ) { - if ( scope.enabled === false ) return; - event.preventDefault(); + sphericalDelta.theta -= angle; - if ( event.button === 0 ) { - if ( scope.noRotate === true ) return; + } - state = STATE.ROTATE; + function rotateUp( angle ) { - rotateStart.set( event.clientX, event.clientY ); + sphericalDelta.phi -= angle; - } else if ( event.button === 1 ) { - if ( scope.noZoom === true ) return; + } - state = STATE.DOLLY; + var panLeft = function () { - dollyStart.set( event.clientX, event.clientY ); + var v = new THREE.Vector3(); - } else if ( event.button === 2 ) { - if ( scope.noPan === true ) return; + return function panLeft( distance, objectMatrix ) { - state = STATE.PAN; + v.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix + v.multiplyScalar( - distance ); - panStart.set( event.clientX, event.clientY ); + panOffset.add( v ); + + }; + + }(); + + var panUp = function () { + + var v = new THREE.Vector3(); + + return function panUp( distance, objectMatrix ) { + + v.setFromMatrixColumn( objectMatrix, 1 ); // get Y column of objectMatrix + v.multiplyScalar( distance ); + + panOffset.add( v ); + + }; + + }(); + + // deltaX and deltaY are in pixels; right and down are positive + var pan = function () { + + var offset = new THREE.Vector3(); + + return function pan( deltaX, deltaY ) { + + var element = scope.domElement === document ? scope.domElement.body : scope.domElement; + + if ( scope.object instanceof THREE.PerspectiveCamera ) { + + // perspective + var position = scope.object.position; + offset.copy( position ).sub( scope.target ); + var targetDistance = offset.length(); + + // half of the fov is center to top of screen + targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 ); + + // we actually don't use screenWidth, since perspective camera is fixed to screen height + panLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix ); + panUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix ); + + } else if ( scope.object instanceof THREE.OrthographicCamera ) { + + // orthographic + panLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix ); + panUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix ); + + } else { + + // camera neither orthographic nor perspective + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' ); + scope.enablePan = false; + + } + + }; + + }(); + + function dollyIn( dollyScale ) { + + if ( scope.object instanceof THREE.PerspectiveCamera ) { + + scale /= dollyScale; + + } else if ( scope.object instanceof THREE.OrthographicCamera ) { + + scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) ); + scope.object.updateProjectionMatrix(); + zoomChanged = true; + + } else { + + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); + scope.enableZoom = false; } - scope.domElement.addEventListener( 'mousemove', onMouseMove, false ); - scope.domElement.addEventListener( 'mouseup', onMouseUp, false ); - scope.dispatchEvent( startEvent ); + } + + function dollyOut( dollyScale ) { + + if ( scope.object instanceof THREE.PerspectiveCamera ) { + + scale *= dollyScale; + + } else if ( scope.object instanceof THREE.OrthographicCamera ) { + + scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) ); + scope.object.updateProjectionMatrix(); + zoomChanged = true; + + } else { + + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); + scope.enableZoom = false; + + } + + } + + // + // event callbacks - update the object state + // + + function handleMouseDownRotate( event ) { + + //console.log( 'handleMouseDownRotate' ); + + rotateStart.set( event.clientX, event.clientY ); + + } + + function handleMouseDownDolly( event ) { + + //console.log( 'handleMouseDownDolly' ); + + dollyStart.set( event.clientX, event.clientY ); + + } + + function handleMouseDownPan( event ) { + + //console.log( 'handleMouseDownPan' ); + + panStart.set( event.clientX, event.clientY ); + + } + + function handleMouseMoveRotate( event ) { + + //console.log( 'handleMouseMoveRotate' ); + + rotateEnd.set( event.clientX, event.clientY ); + rotateDelta.subVectors( rotateEnd, rotateStart ); + + var element = scope.domElement === document ? scope.domElement.body : scope.domElement; + + // rotating across whole screen goes 360 degrees around + rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); + + // rotating up and down along whole screen attempts to go 360, but limited to 180 + rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); + + rotateStart.copy( rotateEnd ); + + scope.update(); + + } + + function handleMouseMoveDolly( event ) { + + //console.log( 'handleMouseMoveDolly' ); + + dollyEnd.set( event.clientX, event.clientY ); + + dollyDelta.subVectors( dollyEnd, dollyStart ); + + if ( dollyDelta.y > 0 ) { + + dollyIn( getZoomScale() ); + + } else if ( dollyDelta.y < 0 ) { + + dollyOut( getZoomScale() ); + + } + + dollyStart.copy( dollyEnd ); + + scope.update(); + + } + + function handleMouseMovePan( event ) { + + //console.log( 'handleMouseMovePan' ); + + panEnd.set( event.clientX, event.clientY ); + + panDelta.subVectors( panEnd, panStart ); + + pan( panDelta.x, panDelta.y ); + + panStart.copy( panEnd ); + + scope.update(); + + } + + function handleMouseUp( event ) { + + // console.log( 'handleMouseUp' ); + + } + + function handleMouseWheel( event ) { + + // console.log( 'handleMouseWheel' ); + + if ( event.deltaY < 0 ) { + + dollyOut( getZoomScale() ); + + } else if ( event.deltaY > 0 ) { + + dollyIn( getZoomScale() ); + + } + + scope.update(); + + } + + function handleKeyDown( event ) { + + //console.log( 'handleKeyDown' ); + + switch ( event.keyCode ) { + + case scope.keys.UP: + pan( 0, scope.keyPanSpeed ); + scope.update(); + break; + + case scope.keys.BOTTOM: + pan( 0, - scope.keyPanSpeed ); + scope.update(); + break; + + case scope.keys.LEFT: + pan( scope.keyPanSpeed, 0 ); + scope.update(); + break; + + case scope.keys.RIGHT: + pan( - scope.keyPanSpeed, 0 ); + scope.update(); + break; + + } + + } + + function handleTouchStartRotate( event ) { + + //console.log( 'handleTouchStartRotate' ); + + rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + + } + + function handleTouchStartDolly( event ) { + + //console.log( 'handleTouchStartDolly' ); + + var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; + var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; + + var distance = Math.sqrt( dx * dx + dy * dy ); + + dollyStart.set( 0, distance ); + + } + + function handleTouchStartPan( event ) { + + //console.log( 'handleTouchStartPan' ); + + panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + + } + + function handleTouchMoveRotate( event ) { + + //console.log( 'handleTouchMoveRotate' ); + + rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + rotateDelta.subVectors( rotateEnd, rotateStart ); + + var element = scope.domElement === document ? scope.domElement.body : scope.domElement; + + // rotating across whole screen goes 360 degrees around + rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); + + // rotating up and down along whole screen attempts to go 360, but limited to 180 + rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); + + rotateStart.copy( rotateEnd ); + + scope.update(); + + } + + function handleTouchMoveDolly( event ) { + + //console.log( 'handleTouchMoveDolly' ); + + var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; + var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; + + var distance = Math.sqrt( dx * dx + dy * dy ); + + dollyEnd.set( 0, distance ); + + dollyDelta.subVectors( dollyEnd, dollyStart ); + + if ( dollyDelta.y > 0 ) { + + dollyOut( getZoomScale() ); + + } else if ( dollyDelta.y < 0 ) { + + dollyIn( getZoomScale() ); + + } + + dollyStart.copy( dollyEnd ); + + scope.update(); + + } + + function handleTouchMovePan( event ) { + + //console.log( 'handleTouchMovePan' ); + + panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + + panDelta.subVectors( panEnd, panStart ); + + pan( panDelta.x, panDelta.y ); + + panStart.copy( panEnd ); + + scope.update(); + + } + + function handleTouchEnd( event ) { + + //console.log( 'handleTouchEnd' ); + + } + + // + // event handlers - FSM: listen for events and reset state + // + + function onMouseDown( event ) { + + if ( scope.enabled === false ) return; + + event.preventDefault(); + + switch ( event.button ) { + + case scope.mouseButtons.ORBIT: + + if ( scope.enableRotate === false ) return; + + handleMouseDownRotate( event ); + + state = STATE.ROTATE; + + break; + + case scope.mouseButtons.ZOOM: + + if ( scope.enableZoom === false ) return; + + handleMouseDownDolly( event ); + + state = STATE.DOLLY; + + break; + + case scope.mouseButtons.PAN: + + if ( scope.enablePan === false ) return; + + handleMouseDownPan( event ); + + state = STATE.PAN; + + break; + + } + + if ( state !== STATE.NONE ) { + + document.addEventListener( 'mousemove', onMouseMove, false ); + document.addEventListener( 'mouseup', onMouseUp, false ); + + scope.dispatchEvent( startEvent ); + + } } @@ -347,135 +713,74 @@ THREE.OrbitControls = function ( object, domElement ) { event.preventDefault(); - var element = scope.domElement === document ? scope.domElement.body : scope.domElement; + switch ( state ) { - if ( state === STATE.ROTATE ) { + case STATE.ROTATE: - if ( scope.noRotate === true ) return; + if ( scope.enableRotate === false ) return; - rotateEnd.set( event.clientX, event.clientY ); - rotateDelta.subVectors( rotateEnd, rotateStart ); + handleMouseMoveRotate( event ); - // rotating across whole screen goes 360 degrees around - scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); + break; - // rotating up and down along whole screen attempts to go 360, but limited to 180 - scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); + case STATE.DOLLY: - rotateStart.copy( rotateEnd ); + if ( scope.enableZoom === false ) return; - } else if ( state === STATE.DOLLY ) { + handleMouseMoveDolly( event ); - if ( scope.noZoom === true ) return; + break; - dollyEnd.set( event.clientX, event.clientY ); - dollyDelta.subVectors( dollyEnd, dollyStart ); + case STATE.PAN: - if ( dollyDelta.y > 0 ) { + if ( scope.enablePan === false ) return; - scope.dollyIn(); + handleMouseMovePan( event ); - } else { - - scope.dollyOut(); - - } - - dollyStart.copy( dollyEnd ); - - } else if ( state === STATE.PAN ) { - - if ( scope.noPan === true ) return; - - panEnd.set( event.clientX, event.clientY ); - panDelta.subVectors( panEnd, panStart ); - - scope.pan( panDelta.x, panDelta.y ); - - panStart.copy( panEnd ); + break; } - scope.update(); - } - function onMouseUp( /* event */ ) { + function onMouseUp( event ) { if ( scope.enabled === false ) return; - scope.domElement.removeEventListener( 'mousemove', onMouseMove, false ); - scope.domElement.removeEventListener( 'mouseup', onMouseUp, false ); + handleMouseUp( event ); + + document.removeEventListener( 'mousemove', onMouseMove, false ); + document.removeEventListener( 'mouseup', onMouseUp, false ); + scope.dispatchEvent( endEvent ); + state = STATE.NONE; } function onMouseWheel( event ) { - if ( scope.enabled === false || scope.noZoom === true ) return; + if ( scope.enabled === false || scope.enableZoom === false || ( state !== STATE.NONE && state !== STATE.ROTATE ) ) return; event.preventDefault(); + event.stopPropagation(); - var delta = 0; + handleMouseWheel( event ); - if ( event.wheelDelta !== undefined ) { // WebKit / Opera / Explorer 9 - - delta = event.wheelDelta; - - } else if ( event.detail !== undefined ) { // Firefox - - delta = - event.detail; - - } - - if ( delta > 0 ) { - - scope.dollyOut(); - - } else { - - scope.dollyIn(); - - } - - scope.update(); - scope.dispatchEvent( startEvent ); + scope.dispatchEvent( startEvent ); // not sure why these are here... scope.dispatchEvent( endEvent ); } function onKeyDown( event ) { - if ( scope.enabled === false || scope.noKeys === true || scope.noPan === true ) return; - - switch ( event.keyCode ) { + if ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return; - case scope.keys.UP: - scope.pan( 0, scope.keyPanSpeed ); - scope.update(); - break; - - case scope.keys.BOTTOM: - scope.pan( 0, - scope.keyPanSpeed ); - scope.update(); - break; - - case scope.keys.LEFT: - scope.pan( scope.keyPanSpeed, 0 ); - scope.update(); - break; - - case scope.keys.RIGHT: - scope.pan( - scope.keyPanSpeed, 0 ); - scope.update(); - break; - - } + handleKeyDown( event ); } - function touchstart( event ) { + function onTouchStart( event ) { if ( scope.enabled === false ) return; @@ -483,32 +788,32 @@ THREE.OrbitControls = function ( object, domElement ) { case 1: // one-fingered touch: rotate - if ( scope.noRotate === true ) return; + if ( scope.enableRotate === false ) return; + + handleTouchStartRotate( event ); state = STATE.TOUCH_ROTATE; - rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); break; case 2: // two-fingered touch: dolly - if ( scope.noZoom === true ) return; + if ( scope.enableZoom === false ) return; + + handleTouchStartDolly( event ); state = STATE.TOUCH_DOLLY; - var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; - var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; - var distance = Math.sqrt( dx * dx + dy * dy ); - dollyStart.set( 0, distance ); break; case 3: // three-fingered touch: pan - if ( scope.noPan === true ) return; + if ( scope.enablePan === false ) return; + + handleTouchStartPan( event ); state = STATE.TOUCH_PAN; - panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); break; default: @@ -517,79 +822,48 @@ THREE.OrbitControls = function ( object, domElement ) { } - scope.dispatchEvent( startEvent ); + if ( state !== STATE.NONE ) { + + scope.dispatchEvent( startEvent ); + + } } - function touchmove( event ) { + function onTouchMove( event ) { if ( scope.enabled === false ) return; event.preventDefault(); event.stopPropagation(); - var element = scope.domElement === document ? scope.domElement.body : scope.domElement; - switch ( event.touches.length ) { case 1: // one-fingered touch: rotate - if ( scope.noRotate === true ) return; - if ( state !== STATE.TOUCH_ROTATE ) return; + if ( scope.enableRotate === false ) return; + if ( state !== STATE.TOUCH_ROTATE ) return; // is this needed?... - rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); - rotateDelta.subVectors( rotateEnd, rotateStart ); + handleTouchMoveRotate( event ); - // rotating across whole screen goes 360 degrees around - scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); - // rotating up and down along whole screen attempts to go 360, but limited to 180 - scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); - - rotateStart.copy( rotateEnd ); - - scope.update(); break; case 2: // two-fingered touch: dolly - if ( scope.noZoom === true ) return; - if ( state !== STATE.TOUCH_DOLLY ) return; + if ( scope.enableZoom === false ) return; + if ( state !== STATE.TOUCH_DOLLY ) return; // is this needed?... - var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; - var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; - var distance = Math.sqrt( dx * dx + dy * dy ); + handleTouchMoveDolly( event ); - dollyEnd.set( 0, distance ); - dollyDelta.subVectors( dollyEnd, dollyStart ); - - if ( dollyDelta.y > 0 ) { - - scope.dollyOut(); - - } else { - - scope.dollyIn(); - - } - - dollyStart.copy( dollyEnd ); - - scope.update(); break; case 3: // three-fingered touch: pan - if ( scope.noPan === true ) return; - if ( state !== STATE.TOUCH_PAN ) return; + if ( scope.enablePan === false ) return; + if ( state !== STATE.TOUCH_PAN ) return; // is this needed?... - panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); - panDelta.subVectors( panEnd, panStart ); - - scope.pan( panDelta.x, panDelta.y ); + handleTouchMovePan( event ); - panStart.copy( panEnd ); - - scope.update(); break; default: @@ -600,26 +874,167 @@ THREE.OrbitControls = function ( object, domElement ) { } - function touchend( /* event */ ) { + function onTouchEnd( event ) { if ( scope.enabled === false ) return; + handleTouchEnd( event ); + scope.dispatchEvent( endEvent ); + state = STATE.NONE; } - this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false ); - this.domElement.addEventListener( 'mousedown', onMouseDown, false ); - this.domElement.addEventListener( 'mousewheel', onMouseWheel, false ); - this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox + function onContextMenu( event ) { - this.domElement.addEventListener( 'touchstart', touchstart, false ); - this.domElement.addEventListener( 'touchend', touchend, false ); - this.domElement.addEventListener( 'touchmove', touchmove, false ); + event.preventDefault(); + + } + + // + + scope.domElement.addEventListener( 'contextmenu', onContextMenu, false ); + + scope.domElement.addEventListener( 'mousedown', onMouseDown, false ); + scope.domElement.addEventListener( 'wheel', onMouseWheel, false ); + + scope.domElement.addEventListener( 'touchstart', onTouchStart, false ); + scope.domElement.addEventListener( 'touchend', onTouchEnd, false ); + scope.domElement.addEventListener( 'touchmove', onTouchMove, false ); window.addEventListener( 'keydown', onKeyDown, false ); + // force an update at start + + this.update(); + }; -THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype ); \ No newline at end of file +THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype ); +THREE.OrbitControls.prototype.constructor = THREE.OrbitControls; + +Object.defineProperties( THREE.OrbitControls.prototype, { + + center: { + + get: function () { + + console.warn( 'THREE.OrbitControls: .center has been renamed to .target' ); + return this.target; + + } + + }, + + // backward compatibility + + noZoom: { + + get: function () { + + console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' ); + return ! this.enableZoom; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' ); + this.enableZoom = ! value; + + } + + }, + + noRotate: { + + get: function () { + + console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' ); + return ! this.enableRotate; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' ); + this.enableRotate = ! value; + + } + + }, + + noPan: { + + get: function () { + + console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' ); + return ! this.enablePan; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' ); + this.enablePan = ! value; + + } + + }, + + noKeys: { + + get: function () { + + console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' ); + return ! this.enableKeys; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' ); + this.enableKeys = ! value; + + } + + }, + + staticMoving: { + + get: function () { + + console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' ); + return ! this.enableDamping; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' ); + this.enableDamping = ! value; + + } + + }, + + dynamicDampingFactor: { + + get: function () { + + console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' ); + return this.dampingFactor; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' ); + this.dampingFactor = value; + + } + + } + +} ); diff --git a/stitchcode/threee/Projector.js b/stitchcode/threee/Projector.js index 03eb19e6..8f2b5a24 100644 --- a/stitchcode/threee/Projector.js +++ b/stitchcode/threee/Projector.js @@ -99,33 +99,32 @@ THREE.RenderableSprite = function () { THREE.Projector = function () { var _object, _objectCount, _objectPool = [], _objectPoolLength = 0, - _vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0, - _face, _faceCount, _facePool = [], _facePoolLength = 0, - _line, _lineCount, _linePool = [], _linePoolLength = 0, - _sprite, _spriteCount, _spritePool = [], _spritePoolLength = 0, + _vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0, + _face, _faceCount, _facePool = [], _facePoolLength = 0, + _line, _lineCount, _linePool = [], _linePoolLength = 0, + _sprite, _spriteCount, _spritePool = [], _spritePoolLength = 0, - _renderData = { objects: [], lights: [], elements: [] }, + _renderData = { objects: [], lights: [], elements: [] }, - _vector3 = new THREE.Vector3(), - _vector4 = new THREE.Vector4(), + _vector3 = new THREE.Vector3(), + _vector4 = new THREE.Vector4(), - _clipBox = new THREE.Box3( new THREE.Vector3( - 1, - 1, - 1 ), new THREE.Vector3( 1, 1, 1 ) ), - _boundingBox = new THREE.Box3(), - _points3 = new Array( 3 ), - _points4 = new Array( 4 ), + _clipBox = new THREE.Box3( new THREE.Vector3( - 1, - 1, - 1 ), new THREE.Vector3( 1, 1, 1 ) ), + _boundingBox = new THREE.Box3(), + _points3 = new Array( 3 ), - _viewMatrix = new THREE.Matrix4(), - _viewProjectionMatrix = new THREE.Matrix4(), + _viewMatrix = new THREE.Matrix4(), + _viewProjectionMatrix = new THREE.Matrix4(), - _modelMatrix, - _modelViewProjectionMatrix = new THREE.Matrix4(), + _modelMatrix, + _modelViewProjectionMatrix = new THREE.Matrix4(), - _normalMatrix = new THREE.Matrix3(), + _normalMatrix = new THREE.Matrix3(), - _frustum = new THREE.Frustum(), + _frustum = new THREE.Frustum(), - _clippedVertex1PositionScreen = new THREE.Vector4(), - _clippedVertex2PositionScreen = new THREE.Vector4(); + _clippedVertex1PositionScreen = new THREE.Vector4(), + _clippedVertex2PositionScreen = new THREE.Vector4(); // @@ -143,7 +142,7 @@ THREE.Projector = function () { }; - this.pickingRay = function ( vector, camera ) { + this.pickingRay = function () { console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' ); @@ -154,6 +153,7 @@ THREE.Projector = function () { var RenderList = function () { var normals = []; + var colors = []; var uvs = []; var object = null; @@ -169,6 +169,7 @@ THREE.Projector = function () { normalMatrix.getNormalMatrix( object.matrixWorld ); normals.length = 0; + colors.length = 0; uvs.length = 0; } @@ -209,6 +210,12 @@ THREE.Projector = function () { } + function pushColor( r, g, b ) { + + colors.push( r, g, b ); + + } + function pushUv( x, y ) { uvs.push( x, y ); @@ -241,17 +248,36 @@ THREE.Projector = function () { var v1 = _vertexPool[ a ]; var v2 = _vertexPool[ b ]; - _line = getNextLineInPool(); + // Clip - _line.id = object.id; - _line.v1.copy( v1 ); - _line.v2.copy( v2 ); - _line.z = ( v1.positionScreen.z + v2.positionScreen.z ) / 2; - _line.renderOrder = object.renderOrder; + v1.positionScreen.copy( v1.position ).applyMatrix4( _modelViewProjectionMatrix ); + v2.positionScreen.copy( v2.position ).applyMatrix4( _modelViewProjectionMatrix ); - _line.material = object.material; + if ( clipLine( v1.positionScreen, v2.positionScreen ) === true ) { - _renderData.elements.push( _line ); + // Perform the perspective divide + v1.positionScreen.multiplyScalar( 1 / v1.positionScreen.w ); + v2.positionScreen.multiplyScalar( 1 / v2.positionScreen.w ); + + _line = getNextLineInPool(); + _line.id = object.id; + _line.v1.copy( v1 ); + _line.v2.copy( v2 ); + _line.z = Math.max( v1.positionScreen.z, v2.positionScreen.z ); + _line.renderOrder = object.renderOrder; + + _line.material = object.material; + + if ( object.material.vertexColors === THREE.VertexColors ) { + + _line.vertexColors[ 0 ].fromArray( colors, a * 3 ); + _line.vertexColors[ 1 ].fromArray( colors, b * 3 ); + + } + + _renderData.elements.push( _line ); + + } } @@ -307,15 +333,65 @@ THREE.Projector = function () { checkBackfaceCulling: checkBackfaceCulling, pushVertex: pushVertex, pushNormal: pushNormal, + pushColor: pushColor, pushUv: pushUv, pushLine: pushLine, pushTriangle: pushTriangle - } + }; }; var renderList = new RenderList(); + function projectObject( object ) { + + if ( object.visible === false ) return; + + if ( object instanceof THREE.Light ) { + + _renderData.lights.push( object ); + + } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Points ) { + + if ( object.material.visible === false ) return; + if ( object.frustumCulled === true && _frustum.intersectsObject( object ) === false ) return; + + addObject( object ); + + } else if ( object instanceof THREE.Sprite ) { + + if ( object.material.visible === false ) return; + if ( object.frustumCulled === true && _frustum.intersectsSprite( object ) === false ) return; + + addObject( object ); + + } + + var children = object.children; + + for ( var i = 0, l = children.length; i < l; i ++ ) { + + projectObject( children[ i ] ); + + } + + } + + function addObject( object ) { + + _object = getNextObjectInPool(); + _object.id = object.id; + _object.object = object; + + _vector3.setFromMatrixPosition( object.matrixWorld ); + _vector3.applyMatrix4( _viewProjectionMatrix ); + _object.z = _vector3.z; + _object.renderOrder = object.renderOrder; + + _renderData.objects.push( _object ); + + } + this.projectScene = function ( scene, camera, sortObjects, sortElements ) { _faceCount = 0; @@ -339,44 +415,7 @@ THREE.Projector = function () { _renderData.objects.length = 0; _renderData.lights.length = 0; - function addObject( object ) { - - _object = getNextObjectInPool(); - _object.id = object.id; - _object.object = object; - - _vector3.setFromMatrixPosition( object.matrixWorld ); - _vector3.applyMatrix4( _viewProjectionMatrix ); - _object.z = _vector3.z; - _object.renderOrder = object.renderOrder; - - _renderData.objects.push( _object ); - - } - - scene.traverseVisible( function ( object ) { - - if ( object instanceof THREE.Light ) { - - _renderData.lights.push( object ); - - } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line ) { - - if ( object.material.visible === false ) return; - if ( object.frustumCulled === true && _frustum.intersectsObject( object ) === false ) return; - - addObject( object ); - - } else if ( object instanceof THREE.Sprite ) { - - if ( object.material.visible === false ) return; - if ( object.frustumCulled === true && _frustum.intersectsSprite( object ) === false ) return; - - addObject( object ); - - } - - } ); + projectObject( scene ); if ( sortObjects === true ) { @@ -386,9 +425,11 @@ THREE.Projector = function () { // - for ( var o = 0, ol = _renderData.objects.length; o < ol; o ++ ) { + var objects = _renderData.objects; - var object = _renderData.objects[ o ].object; + for ( var o = 0, ol = objects.length; o < ol; o ++ ) { + + var object = objects[ o ].object; var geometry = object.geometry; renderList.setObject( object ); @@ -486,8 +527,7 @@ THREE.Projector = function () { var material = object.material; - var isFaceMaterial = material instanceof THREE.MultiMaterial; - var objectMaterials = isFaceMaterial === true ? object.material : null; + var isMultiMaterial = Array.isArray( material ); for ( var v = 0, vl = vertices.length; v < vl; v ++ ) { @@ -525,8 +565,8 @@ THREE.Projector = function () { var face = faces[ f ]; - material = isFaceMaterial === true - ? objectMaterials.materials[ face.materialIndex ] + material = isMultiMaterial === true + ? object.material[ face.materialIndex ] : object.material; if ( material === undefined ) continue; @@ -610,6 +650,8 @@ THREE.Projector = function () { } else if ( object instanceof THREE.Line ) { + _modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix ); + if ( geometry instanceof THREE.BufferGeometry ) { var attributes = geometry.attributes; @@ -624,6 +666,18 @@ THREE.Projector = function () { } + if ( attributes.color !== undefined ) { + + var colors = attributes.color.array; + + for ( var i = 0, l = colors.length; i < l; i += 3 ) { + + renderList.pushColor( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] ); + + } + + } + if ( geometry.index !== null ) { var indices = geometry.index.array; @@ -650,8 +704,6 @@ THREE.Projector = function () { } else if ( geometry instanceof THREE.Geometry ) { - _modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix ); - var vertices = object.geometry.vertices; if ( vertices.length === 0 ) continue; @@ -705,35 +757,33 @@ THREE.Projector = function () { } + } else if ( object instanceof THREE.Points ) { + + _modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix ); + + if ( geometry instanceof THREE.Geometry ) { + + var vertices = object.geometry.vertices; + + for ( var v = 0, vl = vertices.length; v < vl; v ++ ) { + + var vertex = vertices[ v ]; + + _vector4.set( vertex.x, vertex.y, vertex.z, 1 ); + _vector4.applyMatrix4( _modelViewProjectionMatrix ); + + pushPoint( _vector4, object, camera ); + + } + + } + } else if ( object instanceof THREE.Sprite ) { _vector4.set( _modelMatrix.elements[ 12 ], _modelMatrix.elements[ 13 ], _modelMatrix.elements[ 14 ], 1 ); _vector4.applyMatrix4( _viewProjectionMatrix ); - var invW = 1 / _vector4.w; - - _vector4.z *= invW; - - if ( _vector4.z >= - 1 && _vector4.z <= 1 ) { - - _sprite = getNextSpriteInPool(); - _sprite.id = object.id; - _sprite.x = _vector4.x * invW; - _sprite.y = _vector4.y * invW; - _sprite.z = _vector4.z; - _sprite.renderOrder = object.renderOrder; - _sprite.object = object; - - _sprite.rotation = object.rotation; - - _sprite.scale.x = object.scale.x * Math.abs( _sprite.x - ( _vector4.x + camera.projectionMatrix.elements[ 0 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 12 ] ) ); - _sprite.scale.y = object.scale.y * Math.abs( _sprite.y - ( _vector4.y + camera.projectionMatrix.elements[ 5 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 13 ] ) ); - - _sprite.material = object.material; - - _renderData.elements.push( _sprite ); - - } + pushPoint( _vector4, object, camera ); } @@ -749,6 +799,35 @@ THREE.Projector = function () { }; + function pushPoint( _vector4, object, camera ) { + + var invW = 1 / _vector4.w; + + _vector4.z *= invW; + + if ( _vector4.z >= - 1 && _vector4.z <= 1 ) { + + _sprite = getNextSpriteInPool(); + _sprite.id = object.id; + _sprite.x = _vector4.x * invW; + _sprite.y = _vector4.y * invW; + _sprite.z = _vector4.z; + _sprite.renderOrder = object.renderOrder; + _sprite.object = object; + + _sprite.rotation = object.rotation; + + _sprite.scale.x = object.scale.x * Math.abs( _sprite.x - ( _vector4.x + camera.projectionMatrix.elements[ 0 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 12 ] ) ); + _sprite.scale.y = object.scale.y * Math.abs( _sprite.y - ( _vector4.y + camera.projectionMatrix.elements[ 5 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 13 ] ) ); + + _sprite.material = object.material; + + _renderData.elements.push( _sprite ); + + } + + } + // Pools function getNextObjectInPool() { @@ -862,10 +941,11 @@ THREE.Projector = function () { // Calculate the boundary coordinate of each vertex for the near and far clip planes, // Z = -1 and Z = +1, respectively. - bc1near = s1.z + s1.w, - bc2near = s2.z + s2.w, - bc1far = - s1.z + s1.w, - bc2far = - s2.z + s2.w; + + bc1near = s1.z + s1.w, + bc2near = s2.z + s2.w, + bc1far = - s1.z + s1.w, + bc2far = - s2.z + s2.w; if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) { diff --git a/stitchcode/threee/SoftwareRenderer.js b/stitchcode/threee/SoftwareRenderer.js index d1926190..af1661db 100644 --- a/stitchcode/threee/SoftwareRenderer.js +++ b/stitchcode/threee/SoftwareRenderer.js @@ -78,7 +78,7 @@ THREE.SoftwareRenderer = function ( parameters ) { this.supportsVertexTextures = function () {}; this.setFaceCulling = function () {}; - this.setClearColor = function ( color, alpha ) { + this.setClearColor = function ( color ) { clearColor.set( color ); clearColorBuffer( clearColor ); @@ -179,7 +179,7 @@ THREE.SoftwareRenderer = function ( parameters ) { var material = element.material; var shader = getMaterialShader( material ); - if ( !shader ) continue; + if ( ! shader ) continue; if ( element instanceof THREE.RenderableFace ) { @@ -286,8 +286,8 @@ THREE.SoftwareRenderer = function ( parameters ) { drawLine( element.v1.positionScreen, element.v2.positionScreen, - element.vertexColors[0], - element.vertexColors[1], + element.vertexColors[ 0 ], + element.vertexColors[ 1 ], shader, material ); @@ -479,6 +479,7 @@ THREE.SoftwareRenderer = function ( parameters ) { if ( buffer[ colorOffset + 3 ] == 255 ) // Only opaue pixls write to the depth buffer depthBuf[ offset ] = depth; + } } @@ -528,16 +529,6 @@ THREE.SoftwareRenderer = function ( parameters ) { } - function onMaterialUpdate ( event ) { - - var material = event.target; - - material.removeEventListener( 'update', onMaterialUpdate ); - - delete shaders[ material.id ]; - - } - function getMaterialShader( material ) { var id = material.id; @@ -545,9 +536,7 @@ THREE.SoftwareRenderer = function ( parameters ) { if ( shader && material.map && !textures[ material.map.id ] ) delete shaders[ id ]; - if ( shaders[ id ] === undefined ) { - - material.addEventListener( 'update', onMaterialUpdate ); + if ( shaders[ id ] === undefined || material.needsUpdate === true ) { if ( material instanceof THREE.MeshBasicMaterial || material instanceof THREE.MeshLambertMaterial || @@ -581,7 +570,7 @@ THREE.SoftwareRenderer = function ( parameters ) { var texture = new THREE.SoftwareRenderer.Texture(); texture.fromImage( material.map.image ); - if ( !texture.data ) return; + if ( ! texture.data ) return; textures[ material.map.id ] = texture; @@ -636,7 +625,7 @@ THREE.SoftwareRenderer = function ( parameters ) { 'buffer[ colorOffset + 2 ] = material.color.b * (color1.b+color2.b) * 0.5 * 255;', 'buffer[ colorOffset + 3 ] = 255;', 'depthBuf[ offset ] = depth;' - ].join('\n'); + ].join( '\n' ); shader = new Function( 'buffer, depthBuf, offset, depth, color1, color2, material', string ); @@ -657,12 +646,15 @@ THREE.SoftwareRenderer = function ( parameters ) { shaders[ id ] = shader; + material.needsUpdate = false; + } return shader; } + /* function clearRectangle( x1, y1, x2, y2 ) { var xmin = Math.max( Math.min( x1, x2 ), 0 ); @@ -686,6 +678,7 @@ THREE.SoftwareRenderer = function ( parameters ) { } } + */ function drawTriangle( v1, v2, v3, uv1, uv2, uv3, shader, face, material ) { @@ -712,13 +705,12 @@ THREE.SoftwareRenderer = function ( parameters ) { var bHasUV = uv1 && uv2 && uv3; var longestSide = Math.max( - Math.sqrt( (x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2) ), - Math.sqrt( (x2 - x3)*(x2 - x3) + (y2 - y3)*(y2 - y3) ), - Math.sqrt( (x3 - x1)*(x3 - x1) + (y3 - y1)*(y3 - y1) ) + Math.sqrt( ( x1 - x2 ) * ( x1 - x2 ) + ( y1 - y2 ) * ( y1 - y2 ) ), + Math.sqrt( ( x2 - x3 ) * ( x2 - x3 ) + ( y2 - y3 ) * ( y2 - y3 ) ), + Math.sqrt( ( x3 - x1 ) * ( x3 - x1 ) + ( y3 - y1 ) * ( y3 - y1 ) ) ); - if( !(face instanceof THREE.RenderableSprite) - && (longestSide > 100 * fixscale) ) { + if ( ! ( face instanceof THREE.RenderableSprite ) && ( longestSide > 100 * fixscale ) ) { // 1 // |\ @@ -728,11 +720,13 @@ THREE.SoftwareRenderer = function ( parameters ) { // |b\|d\ // |__\__\ // 2 3 - var tempFace = { vertexNormalsModel : [], - color : face.color }; + var tempFace = { vertexNormalsModel: [], color: face.color }; var mpUV12, mpUV23, mpUV31; + if ( bHasUV ) { + if ( mpUVPoolCount === mpUVPool.length ) { + mpUV12 = new THREE.Vector2(); mpUVPool.push( mpUV12 ); ++mpUVPoolCount; @@ -744,27 +738,37 @@ THREE.SoftwareRenderer = function ( parameters ) { mpUV31 = new THREE.Vector2(); mpUVPool.push( mpUV31 ); ++mpUVPoolCount; + } else { + mpUV12 = mpUVPool[ mpUVPoolCount ]; ++mpUVPoolCount; + mpUV23 = mpUVPool[ mpUVPoolCount ]; ++mpUVPoolCount; + mpUV31 = mpUVPool[ mpUVPoolCount ]; ++mpUVPoolCount; + } var weight; - weight = (1 + v2.z) * (v2.w / v1.w) / (1 + v1.z); - mpUV12.copy( uv1 ).multiplyScalar( weight ).add( uv2 ).multiplyScalar( 1 / (weight + 1) ); - weight = (1 + v3.z) * (v3.w / v2.w) / (1 + v2.z); - mpUV23.copy( uv2 ).multiplyScalar( weight ).add( uv3 ).multiplyScalar( 1 / (weight + 1) ); - weight = (1 + v1.z) * (v1.w / v3.w) / (1 + v3.z); - mpUV31.copy( uv3 ).multiplyScalar( weight ).add( uv1 ).multiplyScalar( 1 / (weight + 1) ); + weight = ( 1 + v2.z ) * ( v2.w / v1.w ) / ( 1 + v1.z ); + mpUV12.copy( uv1 ).multiplyScalar( weight ).add( uv2 ).multiplyScalar( 1 / ( weight + 1 ) ); + + weight = ( 1 + v3.z ) * ( v3.w / v2.w ) / ( 1 + v2.z ); + mpUV23.copy( uv2 ).multiplyScalar( weight ).add( uv3 ).multiplyScalar( 1 / ( weight + 1 ) ); + + weight = ( 1 + v1.z ) * ( v1.w / v3.w ) / ( 1 + v3.z ); + mpUV31.copy( uv3 ).multiplyScalar( weight ).add( uv1 ).multiplyScalar( 1 / ( weight + 1 ) ); + } var mpV12, mpV23, mpV31; + if ( mpVPoolCount === mpVPool.length ) { + mpV12 = new THREE.Vector4(); mpVPool.push( mpV12 ); ++mpVPoolCount; @@ -776,13 +780,18 @@ THREE.SoftwareRenderer = function ( parameters ) { mpV31 = new THREE.Vector4(); mpVPool.push( mpV31 ); ++mpVPoolCount; + } else { + mpV12 = mpVPool[ mpVPoolCount ]; ++mpVPoolCount; + mpV23 = mpVPool[ mpVPoolCount ]; ++mpVPoolCount; + mpV31 = mpVPool[ mpVPoolCount ]; ++mpVPoolCount; + } mpV12.copy( v1 ).add( v2 ).multiplyScalar( 0.5 ); @@ -790,8 +799,11 @@ THREE.SoftwareRenderer = function ( parameters ) { mpV31.copy( v3 ).add( v1 ).multiplyScalar( 0.5 ); var mpN12, mpN23, mpN31; - if( bHasNormal ) { + + if ( bHasNormal ) { + if ( mpNPoolCount === mpNPool.length ) { + mpN12 = new THREE.Vector3(); mpNPool.push( mpN12 ); ++mpNPoolCount; @@ -803,53 +815,72 @@ THREE.SoftwareRenderer = function ( parameters ) { mpN31 = new THREE.Vector3(); mpNPool.push( mpN31 ); ++mpNPoolCount; + } else { + mpN12 = mpNPool[ mpNPoolCount ]; ++mpNPoolCount; + mpN23 = mpNPool[ mpNPoolCount ]; ++mpNPoolCount; + mpN31 = mpNPool[ mpNPoolCount ]; ++mpNPoolCount; + } mpN12.copy( face.vertexNormalsModel[ 0 ] ).add( face.vertexNormalsModel[ 1 ] ).normalize(); mpN23.copy( face.vertexNormalsModel[ 1 ] ).add( face.vertexNormalsModel[ 2 ] ).normalize(); mpN31.copy( face.vertexNormalsModel[ 2 ] ).add( face.vertexNormalsModel[ 0 ] ).normalize(); + } // a - if( bHasNormal ) { + if ( bHasNormal ) { + tempFace.vertexNormalsModel[ 0 ] = face.vertexNormalsModel[ 0 ]; tempFace.vertexNormalsModel[ 1 ] = mpN12; tempFace.vertexNormalsModel[ 2 ] = mpN31; + } + drawTriangle( v1, mpV12, mpV31, uv1, mpUV12, mpUV31, shader, tempFace, material ); // b - if( bHasNormal ) { + if ( bHasNormal ) { + tempFace.vertexNormalsModel[ 0 ] = face.vertexNormalsModel[ 1 ]; tempFace.vertexNormalsModel[ 1 ] = mpN23; tempFace.vertexNormalsModel[ 2 ] = mpN12; + } + drawTriangle( v2, mpV23, mpV12, uv2, mpUV23, mpUV12, shader, tempFace, material ); // c - if( bHasNormal ) { + if ( bHasNormal ) { + tempFace.vertexNormalsModel[ 0 ] = mpN12; tempFace.vertexNormalsModel[ 1 ] = mpN23; tempFace.vertexNormalsModel[ 2 ] = mpN31; + } + drawTriangle( mpV12, mpV23, mpV31, mpUV12, mpUV23, mpUV31, shader, tempFace, material ); // d - if( bHasNormal ) { + if ( bHasNormal ) { + tempFace.vertexNormalsModel[ 0 ] = face.vertexNormalsModel[ 2 ]; tempFace.vertexNormalsModel[ 1 ] = mpN31; tempFace.vertexNormalsModel[ 2 ] = mpN23; + } + drawTriangle( v3, mpV31, mpV23, uv3, mpUV31, mpUV23, shader, tempFace, material ); return; + } // Z values (.28 fixed-point) @@ -976,7 +1007,8 @@ THREE.SoftwareRenderer = function ( parameters ) { } - var dnxdx, dnzdy, cbnz; + var dnzdy, cbnz; + if ( bHasNormal ) { // Normal interpolation setup @@ -1369,16 +1401,18 @@ THREE.SoftwareRenderer = function ( parameters ) { function drawLine( v1, v2, color1, color2, shader, material ) { // While the line mode is enable, blockSize has to be changed to 0. - if ( !lineMode ) { + if ( ! lineMode ) { + lineMode = true; blockShift = 0; blockSize = 1 << blockShift; setSize( canvas.width, canvas.height ); + } // TODO: Implement per-pixel z-clipping - if ( v1.z < -1 || v1.z > 1 || v2.z < -1 || v2.z > 1 ) return; + if ( v1.z < - 1 || v1.z > 1 || v2.z < - 1 || v2.z > 1 ) return; var halfLineWidth = Math.floor( ( material.linewidth - 1 ) * 0.5 ); @@ -1422,7 +1456,7 @@ THREE.SoftwareRenderer = function ( parameters ) { crossVector.cross( lookVector ); crossVector.normalize(); - while (length > 0) { + while ( length > 0 ) { // Get this pixel. pixelX = x2 + length * unitX; @@ -1434,7 +1468,7 @@ THREE.SoftwareRenderer = function ( parameters ) { pZ = ( pixelZ + subpixelBias ) >> subpixelBits; // Draw line with line width - for ( var i = -halfLineWidth; i <= halfLineWidth; ++i ) { + for ( var i = - halfLineWidth; i <= halfLineWidth; ++ i ) { // Compute the line pixels. // Get the pixels on the vector that crosses to the line vector @@ -1442,9 +1476,8 @@ THREE.SoftwareRenderer = function ( parameters ) { pY = Math.floor( ( pixelY + crossVector.y * i ) ); // if pixel is over the rect. Continue - if ( rectx1 >= pX || rectx2 <= pX || recty1 >= pY - || recty2 <= pY ) - continue; + if ( rectx1 >= pX || rectx2 <= pX || recty1 >= pY || recty2 <= pY ) + continue; // Find this pixel at which block var blockX = pX >> blockShift; @@ -1464,11 +1497,15 @@ THREE.SoftwareRenderer = function ( parameters ) { var offset = pX + pY * canvasWidth; if ( pZ < zbuffer[ offset ] ) { + shader( data, zbuffer, offset, pZ, color1, color2, material ); + } + } --length; + } } @@ -1526,11 +1563,11 @@ THREE.SoftwareRenderer = function ( parameters ) { }; -THREE.SoftwareRenderer.Texture = function() { +THREE.SoftwareRenderer.Texture = function () { var canvas; - this.fromImage = function( image ) { + this.fromImage = function ( image ) { if ( ! image || image.width <= 0 || image.height <= 0 ) return; diff --git a/stitchcode/threee/three.js b/stitchcode/threee/three.js index 84887242..8006026c 100644 --- a/stitchcode/threee/three.js +++ b/stitchcode/threee/three.js @@ -12,6 +12,19 @@ } + if ( Number.isInteger === undefined ) { + + // Missing in IE + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger + + Number.isInteger = function ( value ) { + + return typeof value === 'number' && isFinite( value ) && Math.floor( value ) === value; + + }; + + } + // if ( Math.sign === undefined ) { @@ -28,7 +41,7 @@ if ( Function.prototype.name === undefined ) { - // Missing in IE9-11. + // Missing in IE // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name Object.defineProperty( Function.prototype, 'name', { @@ -45,7 +58,7 @@ if ( Object.assign === undefined ) { - // Missing in IE. + // Missing in IE // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign ( function () { @@ -96,7 +109,7 @@ function EventDispatcher() {} - EventDispatcher.prototype = { + Object.assign( EventDispatcher.prototype, { addEventListener: function ( type, listener ) { @@ -179,9 +192,9 @@ } - }; + } ); - var REVISION = '84'; + var REVISION = '85'; var MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 }; var CullFaceNone = 0; var CullFaceBack = 1; @@ -487,38 +500,46 @@ } - Vector2.prototype = { + Object.defineProperties( Vector2.prototype, { - constructor: Vector2, + "width" : { + + get: function () { + + return this.x; + + }, + + set: function ( value ) { + + this.x = value; + + } + + }, + + "height" : { + + get: function () { + + return this.y; + + }, + + set: function ( value ) { + + this.y = value; + + } + + } + + } ); + + Object.assign( Vector2.prototype, { isVector2: true, - get width() { - - return this.x; - - }, - - set width( value ) { - - this.x = value; - - }, - - get height() { - - return this.y; - - }, - - set height( value ) { - - this.y = value; - - }, - - // - set: function ( x, y ) { this.x = x; @@ -682,17 +703,8 @@ multiplyScalar: function ( scalar ) { - if ( isFinite( scalar ) ) { - - this.x *= scalar; - this.y *= scalar; - - } else { - - this.x = 0; - this.y = 0; - - } + this.x *= scalar; + this.y *= scalar; return this; @@ -744,17 +756,11 @@ clampScalar: function () { - var min, max; + var min = new Vector2(); + var max = new Vector2(); return function clampScalar( minVal, maxVal ) { - if ( min === undefined ) { - - min = new Vector2(); - max = new Vector2(); - - } - min.set( minVal, minVal ); max.set( maxVal, maxVal ); @@ -957,7 +963,7 @@ } - }; + } ); /** * @author mrdoob / http://mrdoob.com/ @@ -999,7 +1005,6 @@ this.flipY = true; this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml) - // Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap. // // Also changing the encoding after already used by a Material will not automatically make the Material @@ -1014,18 +1019,22 @@ Texture.DEFAULT_IMAGE = undefined; Texture.DEFAULT_MAPPING = UVMapping; - Texture.prototype = { + Object.defineProperty( Texture.prototype, "needsUpdate", { + + set: function ( value ) { + + if ( value === true ) this.version ++; + + } + + } ); + + Object.assign( Texture.prototype, EventDispatcher.prototype, { constructor: Texture, isTexture: true, - set needsUpdate( value ) { - - if ( value === true ) this.version ++; - - }, - clone: function () { return new this.constructor().copy( this ); @@ -1034,6 +1043,8 @@ copy: function ( source ) { + this.name = source.name; + this.image = source.image; this.mipmaps = source.mipmaps.slice( 0 ); @@ -1103,7 +1114,7 @@ var output = { metadata: { - version: 4.4, + version: 4.5, type: 'Texture', generator: 'Texture.toJSON' }, @@ -1238,9 +1249,7 @@ } - }; - - Object.assign( Texture.prototype, EventDispatcher.prototype ); + } ); /** * @author supereggbert / http://www.paulbrunt.co.uk/ @@ -1259,9 +1268,7 @@ } - Vector4.prototype = { - - constructor: Vector4, + Object.assign( Vector4.prototype, { isVector4: true, @@ -1459,21 +1466,10 @@ multiplyScalar: function ( scalar ) { - if ( isFinite( scalar ) ) { - - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; - this.w *= scalar; - - } else { - - this.x = 0; - this.y = 0; - this.z = 0; - this.w = 0; - - } + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; + this.w *= scalar; return this; @@ -1694,17 +1690,11 @@ clampScalar: function () { - var min, max; + var min = new Vector4(); + var max = new Vector4(); return function clampScalar( minVal, maxVal ) { - if ( min === undefined ) { - - min = new Vector4(); - max = new Vector4(); - - } - min.set( minVal, minVal, minVal, minVal ); max.set( maxVal, maxVal, maxVal, maxVal ); @@ -1872,7 +1862,7 @@ } - }; + } ); /** * @author szimek / https://github.com/szimek/ @@ -1909,9 +1899,7 @@ } - WebGLRenderTarget.prototype = { - - constructor: WebGLRenderTarget, + Object.assign( WebGLRenderTarget.prototype, EventDispatcher.prototype, { isWebGLRenderTarget: true, @@ -1960,9 +1948,7 @@ } - }; - - Object.assign( WebGLRenderTarget.prototype, EventDispatcher.prototype ); + } ); /** * @author alteredq / http://alteredqualia.com @@ -1998,61 +1984,151 @@ } - Quaternion.prototype = { + Object.assign( Quaternion, { - constructor: Quaternion, + slerp: function ( qa, qb, qm, t ) { - get x () { - - return this._x; + return qm.copy( qa ).slerp( qb, t ); }, - set x ( value ) { + slerpFlat: function ( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) { - this._x = value; - this.onChangeCallback(); + // fuzz-free, array-based Quaternion SLERP operation + + var x0 = src0[ srcOffset0 + 0 ], + y0 = src0[ srcOffset0 + 1 ], + z0 = src0[ srcOffset0 + 2 ], + w0 = src0[ srcOffset0 + 3 ], + + x1 = src1[ srcOffset1 + 0 ], + y1 = src1[ srcOffset1 + 1 ], + z1 = src1[ srcOffset1 + 2 ], + w1 = src1[ srcOffset1 + 3 ]; + + if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) { + + var s = 1 - t, + + cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, + + dir = ( cos >= 0 ? 1 : - 1 ), + sqrSin = 1 - cos * cos; + + // Skip the Slerp for tiny steps to avoid numeric problems: + if ( sqrSin > Number.EPSILON ) { + + var sin = Math.sqrt( sqrSin ), + len = Math.atan2( sin, cos * dir ); + + s = Math.sin( s * len ) / sin; + t = Math.sin( t * len ) / sin; + + } + + var tDir = t * dir; + + x0 = x0 * s + x1 * tDir; + y0 = y0 * s + y1 * tDir; + z0 = z0 * s + z1 * tDir; + w0 = w0 * s + w1 * tDir; + + // Normalize in case we just did a lerp: + if ( s === 1 - t ) { + + var f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 ); + + x0 *= f; + y0 *= f; + z0 *= f; + w0 *= f; + + } + + } + + dst[ dstOffset ] = x0; + dst[ dstOffset + 1 ] = y0; + dst[ dstOffset + 2 ] = z0; + dst[ dstOffset + 3 ] = w0; + + } + + } ); + + Object.defineProperties( Quaternion.prototype, { + + x: { + + get: function () { + + return this._x; + + }, + + set: function ( value ) { + + this._x = value; + this.onChangeCallback(); + + } }, - get y () { + y: { - return this._y; + get: function () { + + return this._y; + + }, + + set: function ( value ) { + + this._y = value; + this.onChangeCallback(); + + } }, - set y ( value ) { + z: { - this._y = value; - this.onChangeCallback(); + get: function () { + + return this._z; + + }, + + set: function ( value ) { + + this._z = value; + this.onChangeCallback(); + + } }, - get z () { + w: { - return this._z; + get: function () { - }, + return this._w; - set z ( value ) { + }, - this._z = value; - this.onChangeCallback(); + set: function ( value ) { - }, + this._w = value; + this.onChangeCallback(); - get w () { + } - return this._w; + } - }, + } ); - set w ( value ) { - - this._w = value; - this.onChangeCallback(); - - }, + Object.assign( Quaternion.prototype, { set: function ( x, y, z, w ) { @@ -2088,24 +2164,28 @@ setFromEuler: function ( euler, update ) { - if ( (euler && euler.isEuler) === false ) { + if ( ( euler && euler.isEuler ) === false ) { throw new Error( 'THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' ); } + var x = euler._x, y = euler._y, z = euler._z, order = euler.order; + // http://www.mathworks.com/matlabcentral/fileexchange/ // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ // content/SpinCalc.m - var c1 = Math.cos( euler._x / 2 ); - var c2 = Math.cos( euler._y / 2 ); - var c3 = Math.cos( euler._z / 2 ); - var s1 = Math.sin( euler._x / 2 ); - var s2 = Math.sin( euler._y / 2 ); - var s3 = Math.sin( euler._z / 2 ); + var cos = Math.cos; + var sin = Math.sin; - var order = euler.order; + var c1 = cos( x / 2 ); + var c2 = cos( y / 2 ); + var c3 = cos( z / 2 ); + + var s1 = sin( x / 2 ); + var s2 = sin( y / 2 ); + var s3 = sin( z / 2 ); if ( order === 'XYZ' ) { @@ -2237,11 +2317,10 @@ setFromUnitVectors: function () { - // http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final - // assumes direction vectors vFrom and vTo are normalized - var v1, r; + var v1 = new Vector3(); + var r; var EPS = 0.000001; @@ -2435,7 +2514,7 @@ var halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta ); var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, - ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; + ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; this._w = ( w * ratioA + this._w * ratioB ); this._x = ( x * ratioA + this._x * ratioB ); @@ -2493,79 +2572,6 @@ onChangeCallback: function () {} - }; - - Object.assign( Quaternion, { - - slerp: function( qa, qb, qm, t ) { - - return qm.copy( qa ).slerp( qb, t ); - - }, - - slerpFlat: function( - dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) { - - // fuzz-free, array-based Quaternion SLERP operation - - var x0 = src0[ srcOffset0 + 0 ], - y0 = src0[ srcOffset0 + 1 ], - z0 = src0[ srcOffset0 + 2 ], - w0 = src0[ srcOffset0 + 3 ], - - x1 = src1[ srcOffset1 + 0 ], - y1 = src1[ srcOffset1 + 1 ], - z1 = src1[ srcOffset1 + 2 ], - w1 = src1[ srcOffset1 + 3 ]; - - if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) { - - var s = 1 - t, - - cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, - - dir = ( cos >= 0 ? 1 : - 1 ), - sqrSin = 1 - cos * cos; - - // Skip the Slerp for tiny steps to avoid numeric problems: - if ( sqrSin > Number.EPSILON ) { - - var sin = Math.sqrt( sqrSin ), - len = Math.atan2( sin, cos * dir ); - - s = Math.sin( s * len ) / sin; - t = Math.sin( t * len ) / sin; - - } - - var tDir = t * dir; - - x0 = x0 * s + x1 * tDir; - y0 = y0 * s + y1 * tDir; - z0 = z0 * s + z1 * tDir; - w0 = w0 * s + w1 * tDir; - - // Normalize in case we just did a lerp: - if ( s === 1 - t ) { - - var f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 ); - - x0 *= f; - y0 *= f; - z0 *= f; - w0 *= f; - - } - - } - - dst[ dstOffset ] = x0; - dst[ dstOffset + 1 ] = y0; - dst[ dstOffset + 2 ] = z0; - dst[ dstOffset + 3 ] = w0; - - } - } ); /** @@ -2585,9 +2591,7 @@ } - Vector3.prototype = { - - constructor: Vector3, + Object.assign( Vector3.prototype, { isVector3: true, @@ -2782,19 +2786,9 @@ multiplyScalar: function ( scalar ) { - if ( isFinite( scalar ) ) { - - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; - - } else { - - this.x = 0; - this.y = 0; - this.z = 0; - - } + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; return this; @@ -2812,18 +2806,16 @@ applyEuler: function () { - var quaternion; + var quaternion = new Quaternion(); return function applyEuler( euler ) { - if ( (euler && euler.isEuler) === false ) { + if ( ( euler && euler.isEuler ) === false ) { console.error( 'THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.' ); } - if ( quaternion === undefined ) quaternion = new Quaternion(); - return this.applyQuaternion( quaternion.setFromEuler( euler ) ); }; @@ -2832,12 +2824,10 @@ applyAxisAngle: function () { - var quaternion; + var quaternion = new Quaternion(); return function applyAxisAngle( axis, angle ) { - if ( quaternion === undefined ) quaternion = new Quaternion(); - return this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) ); }; @@ -2895,12 +2885,10 @@ project: function () { - var matrix; + var matrix = new Matrix4(); return function project( camera ) { - if ( matrix === undefined ) matrix = new Matrix4(); - matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) ); return this.applyMatrix4( matrix ); @@ -2910,12 +2898,10 @@ unproject: function () { - var matrix; + var matrix = new Matrix4(); return function unproject( camera ) { - if ( matrix === undefined ) matrix = new Matrix4(); - matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) ); return this.applyMatrix4( matrix ); @@ -2989,17 +2975,11 @@ clampScalar: function () { - var min, max; + var min = new Vector3(); + var max = new Vector3(); return function clampScalar( minVal, maxVal ) { - if ( min === undefined ) { - - min = new Vector3(); - max = new Vector3(); - - } - min.set( minVal, minVal, minVal ); max.set( maxVal, maxVal, maxVal ); @@ -3073,6 +3053,8 @@ }, + // TODO lengthSquared? + lengthSq: function () { return this.x * this.x + this.y * this.y + this.z * this.z; @@ -3161,12 +3143,10 @@ projectOnPlane: function () { - var v1; + var v1 = new Vector3(); return function projectOnPlane( planeNormal ) { - if ( v1 === undefined ) v1 = new Vector3(); - v1.copy( this ).projectOnVector( planeNormal ); return this.sub( v1 ); @@ -3180,12 +3160,10 @@ // reflect incident vector off plane orthogonal to normal // normal is assumed to have unit length - var v1; + var v1 = new Vector3(); return function reflect( normal ) { - if ( v1 === undefined ) v1 = new Vector3(); - return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); }; @@ -3222,7 +3200,7 @@ }, - setFromSpherical: function( s ) { + setFromSpherical: function ( s ) { var sinPhiRadius = Math.sin( s.phi ) * s.radius; @@ -3234,7 +3212,7 @@ }, - setFromCylindrical: function( c ) { + setFromCylindrical: function ( c ) { this.x = c.radius * Math.sin( c.theta ); this.y = c.y; @@ -3266,14 +3244,6 @@ setFromMatrixColumn: function ( m, index ) { - if ( typeof m === 'number' ) { - - console.warn( 'THREE.Vector3: setFromMatrixColumn now expects ( matrix, index ).' ); - var temp = m; - m = index; - index = temp; - - } return this.fromArray( m.elements, index * 4 ); @@ -3326,7 +3296,7 @@ } - }; + } ); /** * @author mrdoob / http://mrdoob.com/ @@ -3343,14 +3313,14 @@ function Matrix4() { - this.elements = new Float32Array( [ + this.elements = [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 - ] ); + ]; if ( arguments.length > 0 ) { @@ -3360,9 +3330,7 @@ } - Matrix4.prototype = { - - constructor: Matrix4, + Object.assign( Matrix4.prototype, { isMatrix4: true, @@ -3402,7 +3370,13 @@ copy: function ( m ) { - this.elements.set( m.elements ); + var te = this.elements; + var me = m.elements; + + te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ]; + te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; + te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ]; + te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ]; return this; @@ -3410,8 +3384,7 @@ copyPosition: function ( m ) { - var te = this.elements; - var me = m.elements; + var te = this.elements, me = m.elements; te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; @@ -3446,12 +3419,10 @@ extractRotation: function () { - var v1; + var v1 = new Vector3(); return function extractRotation( m ) { - if ( v1 === undefined ) v1 = new Vector3(); - var te = this.elements; var me = m.elements; @@ -3479,7 +3450,7 @@ makeRotationFromEuler: function ( euler ) { - if ( (euler && euler.isEuler) === false ) { + if ( ( euler && euler.isEuler ) === false ) { console.error( 'THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' ); @@ -3609,7 +3580,7 @@ var te = this.elements; - var x = q.x, y = q.y, z = q.z, w = q.w; + var x = q._x, y = q._y, z = q._z, w = q._w; var x2 = x + x, y2 = y + y, z2 = z + z; var xx = x * x2, xy = x * y2, xz = x * z2; var yy = y * y2, yz = y * z2, zz = z * z2; @@ -3644,40 +3615,39 @@ lookAt: function () { - var x, y, z; + var x = new Vector3(); + var y = new Vector3(); + var z = new Vector3(); return function lookAt( eye, target, up ) { - if ( x === undefined ) { - - x = new Vector3(); - y = new Vector3(); - z = new Vector3(); - - } - var te = this.elements; - z.subVectors( eye, target ).normalize(); + z.subVectors( eye, target ); if ( z.lengthSq() === 0 ) { + // eye and target are in the same position + z.z = 1; } - x.crossVectors( up, z ).normalize(); + z.normalize(); + x.crossVectors( up, z ); if ( x.lengthSq() === 0 ) { + // eye and target are in the same vertical + z.z += 0.0001; - x.crossVectors( up, z ).normalize(); + x.crossVectors( up, z ); } + x.normalize(); y.crossVectors( z, x ); - te[ 0 ] = x.x; te[ 4 ] = y.x; te[ 8 ] = z.x; te[ 1 ] = x.y; te[ 5 ] = y.y; te[ 9 ] = z.y; te[ 2 ] = x.z; te[ 6 ] = y.z; te[ 10 ] = z.z; @@ -3747,21 +3717,6 @@ }, - multiplyToArray: function ( a, b, r ) { - - var te = this.elements; - - this.multiplyMatrices( a, b ); - - r[ 0 ] = te[ 0 ]; r[ 1 ] = te[ 1 ]; r[ 2 ] = te[ 2 ]; r[ 3 ] = te[ 3 ]; - r[ 4 ] = te[ 4 ]; r[ 5 ] = te[ 5 ]; r[ 6 ] = te[ 6 ]; r[ 7 ] = te[ 7 ]; - r[ 8 ] = te[ 8 ]; r[ 9 ] = te[ 9 ]; r[ 10 ] = te[ 10 ]; r[ 11 ] = te[ 11 ]; - r[ 12 ] = te[ 12 ]; r[ 13 ] = te[ 13 ]; r[ 14 ] = te[ 14 ]; r[ 15 ] = te[ 15 ]; - - return this; - - }, - multiplyScalar: function ( s ) { var te = this.elements; @@ -3777,12 +3732,10 @@ applyToBufferAttribute: function () { - var v1; + var v1 = new Vector3(); return function applyToBufferAttribute( attribute ) { - if ( v1 === undefined ) v1 = new Vector3(); - for ( var i = 0, l = attribute.count; i < l; i ++ ) { v1.x = attribute.getX( i ); @@ -4099,17 +4052,11 @@ decompose: function () { - var vector, matrix; + var vector = new Vector3(); + var matrix = new Matrix4(); return function decompose( position, quaternion, scale ) { - if ( vector === undefined ) { - - vector = new Vector3(); - matrix = new Matrix4(); - - } - var te = this.elements; var sx = vector.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length(); @@ -4118,19 +4065,14 @@ // if determine is negative, we need to invert one scale var det = this.determinant(); - if ( det < 0 ) { - - sx = - sx; - - } + if ( det < 0 ) sx = - sx; position.x = te[ 12 ]; position.y = te[ 13 ]; position.z = te[ 14 ]; // scale the rotation part - - matrix.elements.set( this.elements ); // at this point matrix is incomplete so we can't use .copy() + matrix.copy( this ); var invSX = 1 / sx; var invSY = 1 / sy; @@ -4225,7 +4167,7 @@ if ( offset === undefined ) offset = 0; - for( var i = 0; i < 16; i ++ ) { + for ( var i = 0; i < 16; i ++ ) { this.elements[ i ] = array[ i + offset ]; @@ -4252,8 +4194,8 @@ array[ offset + 6 ] = te[ 6 ]; array[ offset + 7 ] = te[ 7 ]; - array[ offset + 8 ] = te[ 8 ]; - array[ offset + 9 ] = te[ 9 ]; + array[ offset + 8 ] = te[ 8 ]; + array[ offset + 9 ] = te[ 9 ]; array[ offset + 10 ] = te[ 10 ]; array[ offset + 11 ] = te[ 11 ]; @@ -4266,7 +4208,31 @@ } - }; + } ); + + /** + * @author alteredq / http://alteredqualia.com/ + */ + + function DataTexture( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) { + + Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); + + this.image = { data: data, width: width, height: height }; + + this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; + this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; + + this.generateMipmaps = false; + this.flipY = false; + this.unpackAlignment = 1; + + } + + DataTexture.prototype = Object.create( Texture.prototype ); + DataTexture.prototype.constructor = DataTexture; + + DataTexture.prototype.isDataTexture = true; /** * @author mrdoob / http://mrdoob.com/ @@ -4372,6 +4338,11 @@ var arrayCacheF32 = []; var arrayCacheI32 = []; + // Float32Array caches used for uploading Matrix uniforms + + var mat4array = new Float32Array( 16 ); + var mat3array = new Float32Array( 9 ); + // Flattening for arrays of vectors and matrices function flatten( array, nBlocks, blockSize ) { @@ -4476,13 +4447,31 @@ function setValue3fm( gl, v ) { - gl.uniformMatrix3fv( this.addr, false, v.elements || v ); + if ( v.elements === undefined ) { + + gl.uniformMatrix3fv( this.addr, false, v ); + + } else { + + mat3array.set( v.elements ); + gl.uniformMatrix3fv( this.addr, false, mat3array ); + + } } function setValue4fm( gl, v ) { - gl.uniformMatrix4fv( this.addr, false, v.elements || v ); + if ( v.elements === undefined ) { + + gl.uniformMatrix4fv( this.addr, false, v ); + + } else { + + mat4array.set( v.elements ); + gl.uniformMatrix4fv( this.addr, false, mat4array ); + + } } @@ -4672,7 +4661,7 @@ } - StructuredUniform.prototype.setValue = function( gl, value ) { + StructuredUniform.prototype.setValue = function ( gl, value ) { // Note: Don't need an extra 'renderer' parameter, since samplers // are not allowed in structured uniforms. @@ -4718,7 +4707,7 @@ // reset RegExp object, because of the early exit of a previous run RePathPart.lastIndex = 0; - for (; ;) { + for ( ; ; ) { var match = RePathPart.exec( path ), matchEnd = RePathPart.lastIndex, @@ -4729,8 +4718,8 @@ if ( idIsIndex ) id = id | 0; // convert to integer - if ( subscript === undefined || - subscript === '[' && matchEnd + 2 === pathLength ) { + if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) { + // bare name or "pure" bottom-level array "[0]" suffix addUniform( container, subscript === undefined ? @@ -4740,10 +4729,10 @@ break; } else { + // step into inner node / create it in case it doesn't exist - var map = container.map, - next = map[ id ]; + var map = container.map, next = map[ id ]; if ( next === undefined ) { @@ -4782,7 +4771,7 @@ } - WebGLUniforms.prototype.setValue = function( gl, name, value ) { + WebGLUniforms.prototype.setValue = function ( gl, name, value ) { var u = this.map[ name ]; @@ -4790,15 +4779,7 @@ }; - WebGLUniforms.prototype.set = function( gl, object, name ) { - - var u = this.map[ name ]; - - if ( u !== undefined ) u.setValue( gl, object[ name ], this.renderer ); - - }; - - WebGLUniforms.prototype.setOptional = function( gl, object, name ) { + WebGLUniforms.prototype.setOptional = function ( gl, object, name ) { var v = object[ name ]; @@ -4809,7 +4790,7 @@ // Static interface - WebGLUniforms.upload = function( gl, seq, values, renderer ) { + WebGLUniforms.upload = function ( gl, seq, values, renderer ) { for ( var i = 0, n = seq.length; i !== n; ++ i ) { @@ -4817,8 +4798,8 @@ v = values[ u.id ]; if ( v.needsUpdate !== false ) { - // note: always updating when .needsUpdate is undefined + // note: always updating when .needsUpdate is undefined u.setValue( gl, v.value, renderer ); } @@ -4827,7 +4808,7 @@ }; - WebGLUniforms.seqWithValue = function( seq, values ) { + WebGLUniforms.seqWithValue = function ( seq, values ) { var r = []; @@ -4842,403 +4823,35 @@ }; - /** - * Uniform Utilities - */ - - var UniformsUtils = { - - merge: function ( uniforms ) { - - var merged = {}; - - for ( var u = 0; u < uniforms.length; u ++ ) { - - var tmp = this.clone( uniforms[ u ] ); - - for ( var p in tmp ) { - - merged[ p ] = tmp[ p ]; - - } - - } - - return merged; - - }, - - clone: function ( uniforms_src ) { - - var uniforms_dst = {}; - - for ( var u in uniforms_src ) { - - uniforms_dst[ u ] = {}; - - for ( var p in uniforms_src[ u ] ) { - - var parameter_src = uniforms_src[ u ][ p ]; - - if ( parameter_src && ( parameter_src.isColor || - parameter_src.isMatrix3 || parameter_src.isMatrix4 || - parameter_src.isVector2 || parameter_src.isVector3 || parameter_src.isVector4 || - parameter_src.isTexture ) ) { - - uniforms_dst[ u ][ p ] = parameter_src.clone(); - - } else if ( Array.isArray( parameter_src ) ) { - - uniforms_dst[ u ][ p ] = parameter_src.slice(); - - } else { - - uniforms_dst[ u ][ p ] = parameter_src; - - } - - } - - } - - return uniforms_dst; - - } - - }; - - var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif\n"; - - var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif\n"; - - var alphatest_fragment = "#ifdef ALPHATEST\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n#endif\n"; - - var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL )\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.specularRoughness );\n\t#endif\n#endif\n"; - - var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif"; - - var begin_vertex = "\nvec3 transformed = vec3( position );\n"; - - var beginnormal_vertex = "\nvec3 objectNormal = vec3( normal );\n"; - - var bsdfs = "float punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\t\tif( decayExponent > 0.0 ) {\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\t\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\t\tfloat maxDistanceCutoffFactor = pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\t\treturn distanceFalloff * maxDistanceCutoffFactor;\n#else\n\t\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n#endif\n\t\t}\n\t\treturn 1.0;\n}\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\n}\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\treturn 1.0 / ( gl * gv );\n}\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( G * D );\n}\nvec2 ltcTextureCoords( const in GeometricContext geometry, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = (LUT_SIZE - 1.0)/LUT_SIZE;\n\tconst float LUT_BIAS = 0.5/LUT_SIZE;\n\tvec3 N = geometry.normal;\n\tvec3 V = geometry.viewDir;\n\tvec3 P = geometry.position;\n\tfloat theta = acos( dot( N, V ) );\n\tvec2 uv = vec2(\n\t\tsqrt( saturate( roughness ) ),\n\t\tsaturate( theta / ( 0.5 * PI ) ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nvoid clipQuadToHorizon( inout vec3 L[5], out int n ) {\n\tint config = 0;\n\tif ( L[0].z > 0.0 ) config += 1;\n\tif ( L[1].z > 0.0 ) config += 2;\n\tif ( L[2].z > 0.0 ) config += 4;\n\tif ( L[3].z > 0.0 ) config += 8;\n\tn = 0;\n\tif ( config == 0 ) {\n\t} else if ( config == 1 ) {\n\t\tn = 3;\n\t\tL[1] = -L[1].z * L[0] + L[0].z * L[1];\n\t\tL[2] = -L[3].z * L[0] + L[0].z * L[3];\n\t} else if ( config == 2 ) {\n\t\tn = 3;\n\t\tL[0] = -L[0].z * L[1] + L[1].z * L[0];\n\t\tL[2] = -L[2].z * L[1] + L[1].z * L[2];\n\t} else if ( config == 3 ) {\n\t\tn = 4;\n\t\tL[2] = -L[2].z * L[1] + L[1].z * L[2];\n\t\tL[3] = -L[3].z * L[0] + L[0].z * L[3];\n\t} else if ( config == 4 ) {\n\t\tn = 3;\n\t\tL[0] = -L[3].z * L[2] + L[2].z * L[3];\n\t\tL[1] = -L[1].z * L[2] + L[2].z * L[1];\n\t} else if ( config == 5 ) {\n\t\tn = 0;\n\t} else if ( config == 6 ) {\n\t\tn = 4;\n\t\tL[0] = -L[0].z * L[1] + L[1].z * L[0];\n\t\tL[3] = -L[3].z * L[2] + L[2].z * L[3];\n\t} else if ( config == 7 ) {\n\t\tn = 5;\n\t\tL[4] = -L[3].z * L[0] + L[0].z * L[3];\n\t\tL[3] = -L[3].z * L[2] + L[2].z * L[3];\n\t} else if ( config == 8 ) {\n\t\tn = 3;\n\t\tL[0] = -L[0].z * L[3] + L[3].z * L[0];\n\t\tL[1] = -L[2].z * L[3] + L[3].z * L[2];\n\t\tL[2] = L[3];\n\t} else if ( config == 9 ) {\n\t\tn = 4;\n\t\tL[1] = -L[1].z * L[0] + L[0].z * L[1];\n\t\tL[2] = -L[2].z * L[3] + L[3].z * L[2];\n\t} else if ( config == 10 ) {\n\t\tn = 0;\n\t} else if ( config == 11 ) {\n\t\tn = 5;\n\t\tL[4] = L[3];\n\t\tL[3] = -L[2].z * L[3] + L[3].z * L[2];\n\t\tL[2] = -L[2].z * L[1] + L[1].z * L[2];\n\t} else if ( config == 12 ) {\n\t\tn = 4;\n\t\tL[1] = -L[1].z * L[2] + L[2].z * L[1];\n\t\tL[0] = -L[0].z * L[3] + L[3].z * L[0];\n\t} else if ( config == 13 ) {\n\t\tn = 5;\n\t\tL[4] = L[3];\n\t\tL[3] = L[2];\n\t\tL[2] = -L[1].z * L[2] + L[2].z * L[1];\n\t\tL[1] = -L[1].z * L[0] + L[0].z * L[1];\n\t} else if ( config == 14 ) {\n\t\tn = 5;\n\t\tL[4] = -L[0].z * L[3] + L[3].z * L[0];\n\t\tL[0] = -L[0].z * L[1] + L[1].z * L[0];\n\t} else if ( config == 15 ) {\n\t\tn = 4;\n\t}\n\tif ( n == 3 )\n\t\tL[3] = L[0];\n\tif ( n == 4 )\n\t\tL[4] = L[0];\n}\nfloat integrateLtcBrdfOverRectEdge( vec3 v1, vec3 v2 ) {\n\tfloat cosTheta = dot( v1, v2 );\n\tfloat theta = acos( cosTheta );\n\tfloat res = cross( v1, v2 ).z * ( ( theta > 0.001 ) ? theta / sin( theta ) : 1.0 );\n\treturn res;\n}\nvoid initRectPoints( const in vec3 pos, const in vec3 halfWidth, const in vec3 halfHeight, out vec3 rectPoints[4] ) {\n\trectPoints[0] = pos - halfWidth - halfHeight;\n\trectPoints[1] = pos + halfWidth - halfHeight;\n\trectPoints[2] = pos + halfWidth + halfHeight;\n\trectPoints[3] = pos - halfWidth + halfHeight;\n}\nvec3 integrateLtcBrdfOverRect( const in GeometricContext geometry, const in mat3 brdfMat, const in vec3 rectPoints[4] ) {\n\tvec3 N = geometry.normal;\n\tvec3 V = geometry.viewDir;\n\tvec3 P = geometry.position;\n\tvec3 T1, T2;\n\tT1 = normalize(V - N * dot( V, N ));\n\tT2 = - cross( N, T1 );\n\tmat3 brdfWrtSurface = brdfMat * transpose( mat3( T1, T2, N ) );\n\tvec3 clippedRect[5];\n\tclippedRect[0] = brdfWrtSurface * ( rectPoints[0] - P );\n\tclippedRect[1] = brdfWrtSurface * ( rectPoints[1] - P );\n\tclippedRect[2] = brdfWrtSurface * ( rectPoints[2] - P );\n\tclippedRect[3] = brdfWrtSurface * ( rectPoints[3] - P );\n\tint n;\n\tclipQuadToHorizon(clippedRect, n);\n\tif ( n == 0 )\n\t\treturn vec3( 0, 0, 0 );\n\tclippedRect[0] = normalize( clippedRect[0] );\n\tclippedRect[1] = normalize( clippedRect[1] );\n\tclippedRect[2] = normalize( clippedRect[2] );\n\tclippedRect[3] = normalize( clippedRect[3] );\n\tclippedRect[4] = normalize( clippedRect[4] );\n\tfloat sum = 0.0;\n\tsum += integrateLtcBrdfOverRectEdge( clippedRect[0], clippedRect[1] );\n\tsum += integrateLtcBrdfOverRectEdge( clippedRect[1], clippedRect[2] );\n\tsum += integrateLtcBrdfOverRectEdge( clippedRect[2], clippedRect[3] );\n\tif (n >= 4)\n\t\tsum += integrateLtcBrdfOverRectEdge( clippedRect[3], clippedRect[4] );\n\tif (n == 5)\n\t\tsum += integrateLtcBrdfOverRectEdge( clippedRect[4], clippedRect[0] );\n\tsum = max( 0.0, sum );\n\tvec3 Lo_i = vec3( sum, sum, sum );\n\treturn Lo_i;\n}\nvec3 Rect_Area_Light_Specular_Reflectance(\n\t\tconst in GeometricContext geometry,\n\t\tconst in vec3 lightPos, const in vec3 lightHalfWidth, const in vec3 lightHalfHeight,\n\t\tconst in float roughness,\n\t\tconst in sampler2D ltcMat, const in sampler2D ltcMag ) {\n\tvec3 rectPoints[4];\n\tinitRectPoints( lightPos, lightHalfWidth, lightHalfHeight, rectPoints );\n\tvec2 uv = ltcTextureCoords( geometry, roughness );\n\tvec4 brdfLtcApproxParams, t;\n\tbrdfLtcApproxParams = texture2D( ltcMat, uv );\n\tt = texture2D( ltcMat, uv );\n\tfloat brdfLtcScalar = texture2D( ltcMag, uv ).a;\n\tmat3 brdfLtcApproxMat = mat3(\n\t\tvec3( 1, 0, t.y ),\n\t\tvec3( 0, t.z, 0 ),\n\t\tvec3( t.w, 0, t.x )\n\t);\n\tvec3 specularReflectance = integrateLtcBrdfOverRect( geometry, brdfLtcApproxMat, rectPoints );\n\tspecularReflectance *= brdfLtcScalar;\n\treturn specularReflectance;\n}\nvec3 Rect_Area_Light_Diffuse_Reflectance(\n\t\tconst in GeometricContext geometry,\n\t\tconst in vec3 lightPos, const in vec3 lightHalfWidth, const in vec3 lightHalfHeight ) {\n\tvec3 rectPoints[4];\n\tinitRectPoints( lightPos, lightHalfWidth, lightHalfHeight, rectPoints );\n\tmat3 diffuseBrdfMat = mat3(1);\n\tvec3 diffuseReflectance = integrateLtcBrdfOverRect( geometry, diffuseBrdfMat, rectPoints );\n\treturn diffuseReflectance;\n}\nvec3 BRDF_Specular_GGX_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n\treturn specularColor * AB.x + AB.y;\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\n}\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\n\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\n}\n"; - - var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\t\tvec3 vSigmaX = dFdx( surf_pos );\n\t\tvec3 vSigmaY = dFdy( surf_pos );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 );\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif\n"; - - var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; ++ i ) {\n\t\tvec4 plane = clippingPlanes[ i ];\n\t\tif ( dot( vViewPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t\t\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; ++ i ) {\n\t\t\tvec4 plane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vViewPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\tif ( clipped ) discard;\n\t\n\t#endif\n#endif\n"; - - var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\t#if ! defined( PHYSICAL ) && ! defined( PHONG )\n\t\tvarying vec3 vViewPosition;\n\t#endif\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif\n"; - - var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvarying vec3 vViewPosition;\n#endif\n"; - - var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n"; - - var color_fragment = "#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif"; - - var color_pars_fragment = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif\n"; - - var color_pars_vertex = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif"; - - var color_vertex = "#ifdef USE_COLOR\n\tvColor.xyz = color.xyz;\n#endif"; - - var common = "#define PI 3.14159265359\n#define PI2 6.28318530718\n#define PI_HALF 1.5707963267949\n#define RECIPROCAL_PI 0.31830988618\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.442695\n#define EPSILON 1e-6\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#define whiteCompliment(a) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract(sin(sn) * c);\n}\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\tfloat distance = dot( planeNormal, point - pointOnPlane );\n\treturn - distance * planeNormal + point;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\n}\nmat3 transpose( const in mat3 v ) {\n\tmat3 tmp;\n\ttmp[0] = vec3(v[0].x, v[1].x, v[2].x);\n\ttmp[1] = vec3(v[0].y, v[1].y, v[2].y);\n\ttmp[2] = vec3(v[0].z, v[1].z, v[2].z);\n\treturn tmp;\n}\n"; - - var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n#define cubeUV_textureSize (1024.0)\nint getFaceFromDirection(vec3 direction) {\n\tvec3 absDirection = abs(direction);\n\tint face = -1;\n\tif( absDirection.x > absDirection.z ) {\n\t\tif(absDirection.x > absDirection.y )\n\t\t\tface = direction.x > 0.0 ? 0 : 3;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\telse {\n\t\tif(absDirection.z > absDirection.y )\n\t\t\tface = direction.z > 0.0 ? 2 : 5;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\treturn face;\n}\n#define cubeUV_maxLods1 (log2(cubeUV_textureSize*0.25) - 1.0)\n#define cubeUV_rangeClamp (exp2((6.0 - 1.0) * 2.0))\nvec2 MipLevelInfo( vec3 vec, float roughnessLevel, float roughness ) {\n\tfloat scale = exp2(cubeUV_maxLods1 - roughnessLevel);\n\tfloat dxRoughness = dFdx(roughness);\n\tfloat dyRoughness = dFdy(roughness);\n\tvec3 dx = dFdx( vec * scale * dxRoughness );\n\tvec3 dy = dFdy( vec * scale * dyRoughness );\n\tfloat d = max( dot( dx, dx ), dot( dy, dy ) );\n\td = clamp(d, 1.0, cubeUV_rangeClamp);\n\tfloat mipLevel = 0.5 * log2(d);\n\treturn vec2(floor(mipLevel), fract(mipLevel));\n}\n#define cubeUV_maxLods2 (log2(cubeUV_textureSize*0.25) - 2.0)\n#define cubeUV_rcpTextureSize (1.0 / cubeUV_textureSize)\nvec2 getCubeUV(vec3 direction, float roughnessLevel, float mipLevel) {\n\tmipLevel = roughnessLevel > cubeUV_maxLods2 - 3.0 ? 0.0 : mipLevel;\n\tfloat a = 16.0 * cubeUV_rcpTextureSize;\n\tvec2 exp2_packed = exp2( vec2( roughnessLevel, mipLevel ) );\n\tvec2 rcp_exp2_packed = vec2( 1.0 ) / exp2_packed;\n\tfloat powScale = exp2_packed.x * exp2_packed.y;\n\tfloat scale = rcp_exp2_packed.x * rcp_exp2_packed.y * 0.25;\n\tfloat mipOffset = 0.75*(1.0 - rcp_exp2_packed.y) * rcp_exp2_packed.x;\n\tbool bRes = mipLevel == 0.0;\n\tscale = bRes && (scale < a) ? a : scale;\n\tvec3 r;\n\tvec2 offset;\n\tint face = getFaceFromDirection(direction);\n\tfloat rcpPowScale = 1.0 / powScale;\n\tif( face == 0) {\n\t\tr = vec3(direction.x, -direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 1) {\n\t\tr = vec3(direction.y, direction.x, direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 2) {\n\t\tr = vec3(direction.z, direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 3) {\n\t\tr = vec3(direction.x, direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse if( face == 4) {\n\t\tr = vec3(direction.y, direction.x, -direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse {\n\t\tr = vec3(direction.z, -direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\tr = normalize(r);\n\tfloat texelOffset = 0.5 * cubeUV_rcpTextureSize;\n\tvec2 s = ( r.yz / abs( r.x ) + vec2( 1.0 ) ) * 0.5;\n\tvec2 base = offset + vec2( texelOffset );\n\treturn base + s * ( scale - 2.0 * texelOffset );\n}\n#define cubeUV_maxLods3 (log2(cubeUV_textureSize*0.25) - 3.0)\nvec4 textureCubeUV(vec3 reflectedDirection, float roughness ) {\n\tfloat roughnessVal = roughness* cubeUV_maxLods3;\n\tfloat r1 = floor(roughnessVal);\n\tfloat r2 = r1 + 1.0;\n\tfloat t = fract(roughnessVal);\n\tvec2 mipInfo = MipLevelInfo(reflectedDirection, r1, roughness);\n\tfloat s = mipInfo.y;\n\tfloat level0 = mipInfo.x;\n\tfloat level1 = level0 + 1.0;\n\tlevel1 = level1 > 5.0 ? 5.0 : level1;\n\tlevel0 += min( floor( s + 0.5 ), 5.0 );\n\tvec2 uv_10 = getCubeUV(reflectedDirection, r1, level0);\n\tvec4 color10 = envMapTexelToLinear(texture2D(envMap, uv_10));\n\tvec2 uv_20 = getCubeUV(reflectedDirection, r2, level0);\n\tvec4 color20 = envMapTexelToLinear(texture2D(envMap, uv_20));\n\tvec4 result = mix(color10, color20, t);\n\treturn vec4(result.rgb, 1.0);\n}\n#endif\n"; - - var defaultnormal_vertex = "#ifdef FLIP_SIDED\n\tobjectNormal = -objectNormal;\n#endif\nvec3 transformedNormal = normalMatrix * objectNormal;\n"; - - var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif\n"; - - var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normal * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );\n#endif\n"; - - var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif\n"; - - var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif\n"; - - var encodings_fragment = " gl_FragColor = linearToOutputTexel( gl_FragColor );\n"; - - var encodings_pars_fragment = "\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );\n}\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );\n}\nvec4 sRGBToLinear( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.w );\n}\nvec4 RGBEToLinear( in vec4 value ) {\n\treturn vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );\n}\nvec4 LinearToRGBE( in vec4 value ) {\n\tfloat maxComponent = max( max( value.r, value.g ), value.b );\n\tfloat fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );\n\treturn vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );\n}\nvec4 RGBMToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.xyz * value.w * maxRange, 1.0 );\n}\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\n\tfloat M = clamp( maxRGB / maxRange, 0.0, 1.0 );\n\tM = ceil( M * 255.0 ) / 255.0;\n\treturn vec4( value.rgb / ( M * maxRange ), M );\n}\nvec4 RGBDToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );\n}\nvec4 LinearToRGBD( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\n\tfloat D = max( maxRange / maxRGB, 1.0 );\n\tD = min( floor( D ) / 255.0, 1.0 );\n\treturn vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\n}\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\nvec4 LinearToLogLuv( in vec4 value ) {\n\tvec3 Xp_Y_XYZp = value.rgb * cLogLuvM;\n\tXp_Y_XYZp = max(Xp_Y_XYZp, vec3(1e-6, 1e-6, 1e-6));\n\tvec4 vResult;\n\tvResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\n\tfloat Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\n\tvResult.w = fract(Le);\n\tvResult.z = (Le - (floor(vResult.w*255.0))/255.0)/255.0;\n\treturn vResult;\n}\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\nvec4 LogLuvToLinear( in vec4 value ) {\n\tfloat Le = value.z * 255.0 + value.w;\n\tvec3 Xp_Y_XYZp;\n\tXp_Y_XYZp.y = exp2((Le - 127.0) / 2.0);\n\tXp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\n\tXp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\n\tvec3 vRGB = Xp_Y_XYZp.rgb * cLogLuvInverseM;\n\treturn vec4( max(vRGB, 0.0), 1.0 );\n}\n"; - - var envmap_fragment = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\tvec2 sampleUV;\n\t\tsampleUV.y = saturate( flipNormal * reflectVec.y * 0.5 + 0.5 );\n\t\tsampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\n\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\tvec3 reflectView = flipNormal * normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) );\n\t\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\tenvColor = envMapTexelToLinear( envColor );\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif\n"; - - var envmap_pars_fragment = "#if defined( USE_ENVMAP ) || defined( PHYSICAL )\n\tuniform float reflectivity;\n\tuniform float envMapIntensity;\n#endif\n#ifdef USE_ENVMAP\n\t#if ! defined( PHYSICAL ) && ( defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) )\n\t\tvarying vec3 vWorldPosition;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\tuniform float flipEnvMap;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( PHYSICAL )\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif\n"; - - var envmap_pars_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif\n"; - - var envmap_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif\n"; - - var fog_vertex = "\n#ifdef USE_FOG\nfogDepth = -mvPosition.z;\n#endif"; - - var fog_pars_vertex = "#ifdef USE_FOG\n varying float fogDepth;\n#endif\n"; - - var fog_fragment = "#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 ) );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, fogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif\n"; - - var fog_pars_fragment = "#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float fogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif\n"; - - var gradientmap_pars_fragment = "#ifdef TOON\n\tuniform sampler2D gradientMap;\n\tvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\t\tfloat dotNL = dot( normal, lightDirection );\n\t\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t\t#ifdef USE_GRADIENTMAP\n\t\t\treturn texture2D( gradientMap, coord ).rgb;\n\t\t#else\n\t\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\n\t\t#endif\n\t}\n#endif\n"; - - var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\treflectedLight.indirectDiffuse += PI * texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n#endif\n"; - - var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif"; - - var lights_lambert_vertex = "vec3 diffuse = vec3( 1.0 );\nGeometricContext geometry;\ngeometry.position = mvPosition.xyz;\ngeometry.normal = normalize( transformedNormal );\ngeometry.viewDir = normalize( -mvPosition.xyz );\nGeometricContext backGeometry;\nbackGeometry.position = geometry.position;\nbackGeometry.normal = -geometry.normal;\nbackGeometry.viewDir = geometry.viewDir;\nvLightFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\n\tvLightBack = vec3( 0.0 );\n#endif\nIncidentLight directLight;\nfloat dotNL;\nvec3 directLightColor_Diffuse;\n#if NUM_POINT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tgetPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tgetSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_DIR_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tgetDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\tvLightFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\n\t\t#endif\n\t}\n#endif\n"; - - var lights_pars = "uniform vec3 ambientLightColor;\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treturn irradiance;\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tdirectLight.color = directionalLight.color;\n\t\tdirectLight.direction = directionalLight.direction;\n\t\tdirectLight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tdirectLight.color = pointLight.color;\n\t\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );\n\t\tdirectLight.visible = ( directLight.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tfloat angleCos = dot( directLight.direction, spotLight.direction );\n\t\tif ( angleCos > spotLight.coneCos ) {\n\t\t\tfloat spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\t\tdirectLight.color = spotLight.color;\n\t\t\tdirectLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tdirectLight.visible = true;\n\t\t} else {\n\t\t\tdirectLight.color = vec3( 0.0 );\n\t\t\tdirectLight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltcMat;\tuniform sampler2D ltcMag;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) {\n\t\tfloat dotNL = dot( geometry.normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tirradiance *= PI;\n\t\t#endif\n\t\treturn irradiance;\n\t}\n#endif\n#if defined( USE_ENVMAP ) && defined( PHYSICAL )\n\tvec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {\n\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\tvec4 envMapColor = textureCubeUV( queryVec, 1.0 );\n\t\t#else\n\t\t\tvec4 envMapColor = vec4( 0.0 );\n\t\t#endif\n\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t}\n\tfloat getSpecularMIPLevel( const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar - 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\n\t}\n\tvec3 getLightProbeIndirectRadiance( const in GeometricContext geometry, const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( -geometry.viewDir, geometry.normal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( -geometry.viewDir, geometry.normal, refractionRatio );\n\t\t#endif\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( blinnShininessExponent, maxMIPLevel );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\tvec4 envMapColor = textureCubeUV(queryReflectVec, BlinnExponentToGGXRoughness(blinnShininessExponent));\n\t\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\t\tvec2 sampleUV;\n\t\t\tsampleUV.y = saturate( reflectVec.y * 0.5 + 0.5 );\n\t\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, sampleUV, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, sampleUV, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0,0.0,1.0 ) );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#endif\n\t\treturn envMapColor.rgb * envMapIntensity;\n\t}\n#endif\n"; - - var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;\n"; - - var lights_phong_pars_fragment = "varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct BlinnPhongMaterial {\n\tvec3\tdiffuseColor;\n\tvec3\tspecularColor;\n\tfloat\tspecularShininess;\n\tfloat\tspecularStrength;\n};\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_BlinnPhong( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 matDiffColor = material.diffuseColor;\n\t\tvec3 matSpecColor = material.specularColor;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = BlinnExponentToGGXRoughness( material.specularShininess );\n\t\tvec3 spec = Rect_Area_Light_Specular_Reflectance(\n\t\t\t\tgeometry,\n\t\t\t\trectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight,\n\t\t\t\troughness,\n\t\t\t\tltcMat, ltcMag );\n\t\tvec3 diff = Rect_Area_Light_Diffuse_Reflectance(\n\t\t\t\tgeometry,\n\t\t\t\trectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight );\n\t\treflectedLight.directSpecular += lightColor * matSpecColor * spec / PI2;\n\t\treflectedLight.directDiffuse += lightColor * matDiffColor * diff / PI2;\n\t}\n#endif\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifdef TOON\n\t\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\t#else\n\t\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\t\tvec3 irradiance = dotNL * directLight.color;\n\t#endif\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)\n"; - - var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nmaterial.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );\n#ifdef STANDARD\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.clearCoat = saturate( clearCoat );\tmaterial.clearCoatRoughness = clamp( clearCoatRoughness, 0.04, 1.0 );\n#endif\n"; - - var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3\tdiffuseColor;\n\tfloat\tspecularRoughness;\n\tvec3\tspecularColor;\n\t#ifndef STANDARD\n\t\tfloat clearCoat;\n\t\tfloat clearCoatRoughness;\n\t#endif\n};\n#define MAXIMUM_SPECULAR_COEFFICIENT 0.16\n#define DEFAULT_SPECULAR_COEFFICIENT 0.04\nfloat clearCoatDHRApprox( const in float roughness, const in float dotNL ) {\n\treturn DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 matDiffColor = material.diffuseColor;\n\t\tvec3 matSpecColor = material.specularColor;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.specularRoughness;\n\t\tvec3 spec = Rect_Area_Light_Specular_Reflectance(\n\t\t\t\tgeometry,\n\t\t\t\trectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight,\n\t\t\t\troughness,\n\t\t\t\tltcMat, ltcMag );\n\t\tvec3 diff = Rect_Area_Light_Diffuse_Reflectance(\n\t\t\t\tgeometry,\n\t\t\t\trectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight );\n\t\treflectedLight.directSpecular += lightColor * matSpecColor * spec;\n\t\treflectedLight.directDiffuse += lightColor * matDiffColor * diff;\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\t#ifndef STANDARD\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry, material.specularColor, material.specularRoughness );\n\treflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\t#ifndef STANDARD\n\t\treflectedLight.directSpecular += irradiance * material.clearCoat * BRDF_Specular_GGX( directLight, geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 clearCoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifndef STANDARD\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\tfloat dotNL = dotNV;\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.indirectSpecular += ( 1.0 - clearCoatDHR ) * radiance * BRDF_Specular_GGX_Environment( geometry, material.specularColor, material.specularRoughness );\n\t#ifndef STANDARD\n\t\treflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * BRDF_Specular_GGX_Environment( geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\n#define Material_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.specularRoughness )\n#define Material_ClearCoat_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.clearCoatRoughness )\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}\n"; - - var lights_template = "\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = normalize( vViewPosition );\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( pointLight.shadow, directLight.visible ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( directionalLight.shadow, directLight.visible ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#ifdef USE_LIGHTMAP\n\t\tvec3 lightMapIrradiance = texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tlightMapIrradiance *= PI;\n\t\t#endif\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t}\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tirradiance += getLightProbeIndirectIrradiance( geometry, 8 );\n\t#endif\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tvec3 radiance = getLightProbeIndirectRadiance( geometry, Material_BlinnShininessExponent( material ), 8 );\n\t#ifndef STANDARD\n\t\tvec3 clearCoatRadiance = getLightProbeIndirectRadiance( geometry, Material_ClearCoat_BlinnShininessExponent( material ), 8 );\n\t#else\n\t\tvec3 clearCoatRadiance = vec3( 0.0 );\n\t#endif\n\tRE_IndirectSpecular( radiance, clearCoatRadiance, geometry, material, reflectedLight );\n#endif\n"; - - var logdepthbuf_fragment = "#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)\n\tgl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;\n#endif"; - - var logdepthbuf_pars_fragment = "#ifdef USE_LOGDEPTHBUF\n\tuniform float logDepthBufFC;\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#endif\n#endif\n"; - - var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#endif\n\tuniform float logDepthBufFC;\n#endif"; - - var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\tgl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC;\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t#else\n\t\tgl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;\n\t#endif\n#endif\n"; - - var map_fragment = "#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif\n"; - - var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n"; - - var map_particle_fragment = "#ifdef USE_MAP\n\tvec4 mapTexel = texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\n#endif\n"; - - var map_particle_pars_fragment = "#ifdef USE_MAP\n\tuniform vec4 offsetRepeat;\n\tuniform sampler2D map;\n#endif\n"; - - var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.r;\n#endif\n"; - - var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif"; - - var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\n\tobjectNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\n\tobjectNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\n\tobjectNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\n#endif\n"; - - var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\t#ifndef USE_MORPHNORMALS\n\tuniform float morphTargetInfluences[ 8 ];\n\t#else\n\tuniform float morphTargetInfluences[ 4 ];\n\t#endif\n#endif"; - - var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\n\ttransformed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\n\ttransformed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\n\ttransformed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n\t#ifndef USE_MORPHNORMALS\n\ttransformed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\n\ttransformed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\n\ttransformed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\n\ttransformed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n\t#endif\n#endif\n"; - - var normal_flip = "#ifdef DOUBLE_SIDED\n\tfloat flipNormal = ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n#else\n\tfloat flipNormal = 1.0;\n#endif\n"; - - var normal_fragment = "#ifdef FLAT_SHADED\n\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\n\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal ) * flipNormal;\n#endif\n#ifdef USE_NORMALMAP\n\tnormal = perturbNormal2Arb( -vViewPosition, normal );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif\n"; - - var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tvec3 S = normalize( q0 * st1.t - q1 * st0.t );\n\t\tvec3 T = normalize( -q0 * st1.s + q1 * st0.s );\n\t\tvec3 N = normalize( surf_norm );\n\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\tmapN.xy = normalScale * mapN.xy;\n\t\tmat3 tsn = mat3( S, T, N );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif\n"; - - var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 1.0 - 2.0 * rgb.xyz;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn (( near + viewZ ) * far ) / (( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}\n"; - - var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif\n"; - - var project_vertex = "#ifdef USE_SKINNING\n\tvec4 mvPosition = modelViewMatrix * skinned;\n#else\n\tvec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\n#endif\ngl_Position = projectionMatrix * mvPosition;\n"; - - var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.r;\n#endif\n"; - - var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif"; - - var shadowmap_pars_fragment = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tfloat texture2DShadowLerp( sampler2D depths, vec2 size, vec2 uv, float compare ) {\n\t\tconst vec2 offset = vec2( 0.0, 1.0 );\n\t\tvec2 texelSize = vec2( 1.0 ) / size;\n\t\tvec2 centroidUV = floor( uv * size + 0.5 ) / size;\n\t\tfloat lb = texture2DCompare( depths, centroidUV + texelSize * offset.xx, compare );\n\t\tfloat lt = texture2DCompare( depths, centroidUV + texelSize * offset.xy, compare );\n\t\tfloat rb = texture2DCompare( depths, centroidUV + texelSize * offset.yx, compare );\n\t\tfloat rt = texture2DCompare( depths, centroidUV + texelSize * offset.yy, compare );\n\t\tvec2 f = fract( uv * size + 0.5 );\n\t\tfloat a = mix( lb, lt, f.y );\n\t\tfloat b = mix( rb, rt, f.y );\n\t\tfloat c = mix( a, b, f.x );\n\t\treturn c;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\treturn (\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn 1.0;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\tfloat dp = ( length( lightToPosition ) - shadowBias ) / 1000.0;\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif\n"; - - var shadowmap_pars_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n#endif\n"; - - var shadowmap_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n#endif\n"; - - var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\tDirectionalLight directionalLight;\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tshadow *= bool( directionalLight.shadow ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\tSpotLight spotLight;\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tshadow *= bool( spotLight.shadow ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\tPointLight pointLight;\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tshadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#endif\n\treturn shadow;\n}\n"; - - var skinbase_vertex = "#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif"; - - var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\t#ifdef BONE_TEXTURE\n\t\tuniform sampler2D boneTexture;\n\t\tuniform int boneTextureWidth;\n\t\tuniform int boneTextureHeight;\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tfloat j = i * 4.0;\n\t\t\tfloat x = mod( j, float( boneTextureWidth ) );\n\t\t\tfloat y = floor( j / float( boneTextureWidth ) );\n\t\t\tfloat dx = 1.0 / float( boneTextureWidth );\n\t\t\tfloat dy = 1.0 / float( boneTextureHeight );\n\t\t\ty = dy * ( y + 0.5 );\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\t\treturn bone;\n\t\t}\n\t#else\n\t\tuniform mat4 boneMatrices[ MAX_BONES ];\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tmat4 bone = boneMatrices[ int(i) ];\n\t\t\treturn bone;\n\t\t}\n\t#endif\n#endif\n"; - - var skinning_vertex = "#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\tskinned = bindMatrixInverse * skinned;\n#endif\n"; - - var skinnormal_vertex = "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n#endif\n"; - - var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif"; - - var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif"; - - var tonemapping_fragment = "#if defined( TONE_MAPPING )\n gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif\n"; - - var tonemapping_pars_fragment = "#define saturate(a) clamp( a, 0.0, 1.0 )\nuniform float toneMappingExposure;\nuniform float toneMappingWhitePoint;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\n#define Uncharted2Helper( x ) max( ( ( x * ( 0.15 * x + 0.10 * 0.50 ) + 0.20 * 0.02 ) / ( x * ( 0.15 * x + 0.50 ) + 0.20 * 0.30 ) ) - 0.02 / 0.30, vec3( 0.0 ) )\nvec3 Uncharted2ToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\n"; - - var uv_pars_fragment = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n#endif"; - - var uv_pars_vertex = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n\tuniform vec4 offsetRepeat;\n#endif\n"; - - var uv_vertex = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvUv = uv * offsetRepeat.zw + offsetRepeat.xy;\n#endif"; - - var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif"; - - var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n#endif"; - - var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = uv2;\n#endif"; - - var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( PHYSICAL ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )\n\t#ifdef USE_SKINNING\n\t\tvec4 worldPosition = modelMatrix * skinned;\n\t#else\n\t\tvec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\n\t#endif\n#endif\n"; - - var cube_frag = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldPosition;\n#include \nvoid main() {\n\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\n\tgl_FragColor.a *= opacity;\n}\n"; - - var cube_vert = "varying vec3 vWorldPosition;\n#include \nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}\n"; - - var depth_frag = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( gl_FragCoord.z ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( gl_FragCoord.z );\n\t#endif\n}\n"; - - var depth_vert = "#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; - - var distanceRGBA_frag = "uniform vec3 lightPos;\nvarying vec4 vWorldPosition;\n#include \n#include \n#include \nvoid main () {\n\t#include \n\tgl_FragColor = packDepthToRGBA( length( vWorldPosition.xyz - lightPos.xyz ) / 1000.0 );\n}\n"; - - var distanceRGBA_vert = "varying vec4 vWorldPosition;\n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition;\n}\n"; - - var equirect_frag = "uniform sampler2D tEquirect;\nuniform float tFlip;\nvarying vec3 vWorldPosition;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldPosition );\n\tvec2 sampleUV;\n\tsampleUV.y = saturate( tFlip * direction.y * -0.5 + 0.5 );\n\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n}\n"; - - var equirect_vert = "varying vec3 vWorldPosition;\n#include \nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}\n"; - - var linedashed_frag = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; - - var linedashed_vert = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvLineDistance = scale * lineDistance;\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}\n"; - - var meshbasic_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\treflectedLight.indirectDiffuse += texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; - - var meshbasic_vert = "#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#ifdef USE_ENVMAP\n\t#include \n\t#include \n\t#include \n\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; - - var meshlambert_frag = "uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\treflectedLight.indirectDiffuse = getAmbientLightIrradiance( ambientLightColor );\n\t#include \n\treflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\n\t#else\n\t\treflectedLight.directDiffuse = vLightFront;\n\t#endif\n\treflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();\n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; - - var meshlambert_vert = "#define LAMBERT\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; - - var meshphong_frag = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; - - var meshphong_vert = "#define PHONG\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; - - var meshphysical_frag = "#define PHYSICAL\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifndef STANDARD\n\tuniform float clearCoat;\n\tuniform float clearCoatRoughness;\n#endif\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; - - var meshphysical_vert = "#define PHYSICAL\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}\n"; - - var normal_frag = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n}\n"; - - var normal_vert = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}\n"; - - var points_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; - - var points_vert = "uniform float size;\nuniform float scale;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#ifdef USE_SIZEATTENUATION\n\t\tgl_PointSize = size * ( scale / - mvPosition.z );\n\t#else\n\t\tgl_PointSize = size;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; - - var shadow_frag = "uniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tgl_FragColor = vec4( 0.0, 0.0, 0.0, opacity * ( 1.0 - getShadowMask() ) );\n}\n"; - - var shadow_vert = "#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; - - var ShaderChunk = { - alphamap_fragment: alphamap_fragment, - alphamap_pars_fragment: alphamap_pars_fragment, - alphatest_fragment: alphatest_fragment, - aomap_fragment: aomap_fragment, - aomap_pars_fragment: aomap_pars_fragment, - begin_vertex: begin_vertex, - beginnormal_vertex: beginnormal_vertex, - bsdfs: bsdfs, - bumpmap_pars_fragment: bumpmap_pars_fragment, - clipping_planes_fragment: clipping_planes_fragment, - clipping_planes_pars_fragment: clipping_planes_pars_fragment, - clipping_planes_pars_vertex: clipping_planes_pars_vertex, - clipping_planes_vertex: clipping_planes_vertex, - color_fragment: color_fragment, - color_pars_fragment: color_pars_fragment, - color_pars_vertex: color_pars_vertex, - color_vertex: color_vertex, - common: common, - cube_uv_reflection_fragment: cube_uv_reflection_fragment, - defaultnormal_vertex: defaultnormal_vertex, - displacementmap_pars_vertex: displacementmap_pars_vertex, - displacementmap_vertex: displacementmap_vertex, - emissivemap_fragment: emissivemap_fragment, - emissivemap_pars_fragment: emissivemap_pars_fragment, - encodings_fragment: encodings_fragment, - encodings_pars_fragment: encodings_pars_fragment, - envmap_fragment: envmap_fragment, - envmap_pars_fragment: envmap_pars_fragment, - envmap_pars_vertex: envmap_pars_vertex, - envmap_vertex: envmap_vertex, - fog_vertex: fog_vertex, - fog_pars_vertex: fog_pars_vertex, - fog_fragment: fog_fragment, - fog_pars_fragment: fog_pars_fragment, - gradientmap_pars_fragment: gradientmap_pars_fragment, - lightmap_fragment: lightmap_fragment, - lightmap_pars_fragment: lightmap_pars_fragment, - lights_lambert_vertex: lights_lambert_vertex, - lights_pars: lights_pars, - lights_phong_fragment: lights_phong_fragment, - lights_phong_pars_fragment: lights_phong_pars_fragment, - lights_physical_fragment: lights_physical_fragment, - lights_physical_pars_fragment: lights_physical_pars_fragment, - lights_template: lights_template, - logdepthbuf_fragment: logdepthbuf_fragment, - logdepthbuf_pars_fragment: logdepthbuf_pars_fragment, - logdepthbuf_pars_vertex: logdepthbuf_pars_vertex, - logdepthbuf_vertex: logdepthbuf_vertex, - map_fragment: map_fragment, - map_pars_fragment: map_pars_fragment, - map_particle_fragment: map_particle_fragment, - map_particle_pars_fragment: map_particle_pars_fragment, - metalnessmap_fragment: metalnessmap_fragment, - metalnessmap_pars_fragment: metalnessmap_pars_fragment, - morphnormal_vertex: morphnormal_vertex, - morphtarget_pars_vertex: morphtarget_pars_vertex, - morphtarget_vertex: morphtarget_vertex, - normal_flip: normal_flip, - normal_fragment: normal_fragment, - normalmap_pars_fragment: normalmap_pars_fragment, - packing: packing, - premultiplied_alpha_fragment: premultiplied_alpha_fragment, - project_vertex: project_vertex, - roughnessmap_fragment: roughnessmap_fragment, - roughnessmap_pars_fragment: roughnessmap_pars_fragment, - shadowmap_pars_fragment: shadowmap_pars_fragment, - shadowmap_pars_vertex: shadowmap_pars_vertex, - shadowmap_vertex: shadowmap_vertex, - shadowmask_pars_fragment: shadowmask_pars_fragment, - skinbase_vertex: skinbase_vertex, - skinning_pars_vertex: skinning_pars_vertex, - skinning_vertex: skinning_vertex, - skinnormal_vertex: skinnormal_vertex, - specularmap_fragment: specularmap_fragment, - specularmap_pars_fragment: specularmap_pars_fragment, - tonemapping_fragment: tonemapping_fragment, - tonemapping_pars_fragment: tonemapping_pars_fragment, - uv_pars_fragment: uv_pars_fragment, - uv_pars_vertex: uv_pars_vertex, - uv_vertex: uv_vertex, - uv2_pars_fragment: uv2_pars_fragment, - uv2_pars_vertex: uv2_pars_vertex, - uv2_vertex: uv2_vertex, - worldpos_vertex: worldpos_vertex, - - cube_frag: cube_frag, - cube_vert: cube_vert, - depth_frag: depth_frag, - depth_vert: depth_vert, - distanceRGBA_frag: distanceRGBA_frag, - distanceRGBA_vert: distanceRGBA_vert, - equirect_frag: equirect_frag, - equirect_vert: equirect_vert, - linedashed_frag: linedashed_frag, - linedashed_vert: linedashed_vert, - meshbasic_frag: meshbasic_frag, - meshbasic_vert: meshbasic_vert, - meshlambert_frag: meshlambert_frag, - meshlambert_vert: meshlambert_vert, - meshphong_frag: meshphong_frag, - meshphong_vert: meshphong_vert, - meshphysical_frag: meshphysical_frag, - meshphysical_vert: meshphysical_vert, - normal_frag: normal_frag, - normal_vert: normal_vert, - points_frag: points_frag, - points_vert: points_vert, - shadow_frag: shadow_frag, - shadow_vert: shadow_vert - }; - /** * @author mrdoob / http://mrdoob.com/ */ + var ColorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF, + 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2, + 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50, + 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B, + 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B, + 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F, + 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3, + 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222, + 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700, + 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4, + 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00, + 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3, + 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA, + 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32, + 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3, + 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC, + 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD, + 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6, + 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9, + 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F, + 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE, + 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA, + 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0, + 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 }; + function Color( r, g, b ) { if ( g === undefined && b === undefined ) { @@ -5252,9 +4865,7 @@ } - Color.prototype = { - - constructor: Color, + Object.assign( Color.prototype, { isColor: true, @@ -5729,56 +5340,7 @@ } - }; - - var ColorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF, - 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2, - 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50, - 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B, - 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B, - 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F, - 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3, - 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222, - 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700, - 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4, - 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00, - 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3, - 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA, - 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32, - 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3, - 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC, - 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD, - 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6, - 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9, - 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F, - 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE, - 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA, - 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0, - 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 }; - - /** - * @author alteredq / http://alteredqualia.com/ - */ - - function DataTexture( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) { - - Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); - - this.image = { data: data, width: width, height: height }; - - this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; - this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; - - this.generateMipmaps = false; - this.flipY = false; - this.unpackAlignment = 1; - - } - - DataTexture.prototype = Object.create( Texture.prototype ); - DataTexture.prototype.constructor = DataTexture; - - DataTexture.prototype.isDataTexture = true; + } ); /** * Uniforms library for shared webgl shaders @@ -5952,6 +5514,405 @@ }; + /** + * Uniform Utilities + */ + + var UniformsUtils = { + + merge: function ( uniforms ) { + + var merged = {}; + + for ( var u = 0; u < uniforms.length; u ++ ) { + + var tmp = this.clone( uniforms[ u ] ); + + for ( var p in tmp ) { + + merged[ p ] = tmp[ p ]; + + } + + } + + return merged; + + }, + + clone: function ( uniforms_src ) { + + var uniforms_dst = {}; + + for ( var u in uniforms_src ) { + + uniforms_dst[ u ] = {}; + + for ( var p in uniforms_src[ u ] ) { + + var parameter_src = uniforms_src[ u ][ p ]; + + if ( parameter_src && ( parameter_src.isColor || + parameter_src.isMatrix3 || parameter_src.isMatrix4 || + parameter_src.isVector2 || parameter_src.isVector3 || parameter_src.isVector4 || + parameter_src.isTexture ) ) { + + uniforms_dst[ u ][ p ] = parameter_src.clone(); + + } else if ( Array.isArray( parameter_src ) ) { + + uniforms_dst[ u ][ p ] = parameter_src.slice(); + + } else { + + uniforms_dst[ u ][ p ] = parameter_src; + + } + + } + + } + + return uniforms_dst; + + } + + }; + + var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif\n"; + + var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif\n"; + + var alphatest_fragment = "#ifdef ALPHATEST\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n#endif\n"; + + var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL )\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.specularRoughness );\n\t#endif\n#endif\n"; + + var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif"; + + var begin_vertex = "\nvec3 transformed = vec3( position );\n"; + + var beginnormal_vertex = "\nvec3 objectNormal = vec3( normal );\n"; + + var bsdfs = "float punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\t\tif( decayExponent > 0.0 ) {\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\t\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\t\tfloat maxDistanceCutoffFactor = pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\t\treturn distanceFalloff * maxDistanceCutoffFactor;\n#else\n\t\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n#endif\n\t\t}\n\t\treturn 1.0;\n}\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\n}\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\treturn 1.0 / ( gl * gv );\n}\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( G * D );\n}\nvec2 ltcTextureCoords( const in GeometricContext geometry, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = (LUT_SIZE - 1.0)/LUT_SIZE;\n\tconst float LUT_BIAS = 0.5/LUT_SIZE;\n\tvec3 N = geometry.normal;\n\tvec3 V = geometry.viewDir;\n\tvec3 P = geometry.position;\n\tfloat theta = acos( dot( N, V ) );\n\tvec2 uv = vec2(\n\t\tsqrt( saturate( roughness ) ),\n\t\tsaturate( theta / ( 0.5 * PI ) ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nvoid clipQuadToHorizon( inout vec3 L[5], out int n ) {\n\tint config = 0;\n\tif ( L[0].z > 0.0 ) config += 1;\n\tif ( L[1].z > 0.0 ) config += 2;\n\tif ( L[2].z > 0.0 ) config += 4;\n\tif ( L[3].z > 0.0 ) config += 8;\n\tn = 0;\n\tif ( config == 0 ) {\n\t} else if ( config == 1 ) {\n\t\tn = 3;\n\t\tL[1] = -L[1].z * L[0] + L[0].z * L[1];\n\t\tL[2] = -L[3].z * L[0] + L[0].z * L[3];\n\t} else if ( config == 2 ) {\n\t\tn = 3;\n\t\tL[0] = -L[0].z * L[1] + L[1].z * L[0];\n\t\tL[2] = -L[2].z * L[1] + L[1].z * L[2];\n\t} else if ( config == 3 ) {\n\t\tn = 4;\n\t\tL[2] = -L[2].z * L[1] + L[1].z * L[2];\n\t\tL[3] = -L[3].z * L[0] + L[0].z * L[3];\n\t} else if ( config == 4 ) {\n\t\tn = 3;\n\t\tL[0] = -L[3].z * L[2] + L[2].z * L[3];\n\t\tL[1] = -L[1].z * L[2] + L[2].z * L[1];\n\t} else if ( config == 5 ) {\n\t\tn = 0;\n\t} else if ( config == 6 ) {\n\t\tn = 4;\n\t\tL[0] = -L[0].z * L[1] + L[1].z * L[0];\n\t\tL[3] = -L[3].z * L[2] + L[2].z * L[3];\n\t} else if ( config == 7 ) {\n\t\tn = 5;\n\t\tL[4] = -L[3].z * L[0] + L[0].z * L[3];\n\t\tL[3] = -L[3].z * L[2] + L[2].z * L[3];\n\t} else if ( config == 8 ) {\n\t\tn = 3;\n\t\tL[0] = -L[0].z * L[3] + L[3].z * L[0];\n\t\tL[1] = -L[2].z * L[3] + L[3].z * L[2];\n\t\tL[2] = L[3];\n\t} else if ( config == 9 ) {\n\t\tn = 4;\n\t\tL[1] = -L[1].z * L[0] + L[0].z * L[1];\n\t\tL[2] = -L[2].z * L[3] + L[3].z * L[2];\n\t} else if ( config == 10 ) {\n\t\tn = 0;\n\t} else if ( config == 11 ) {\n\t\tn = 5;\n\t\tL[4] = L[3];\n\t\tL[3] = -L[2].z * L[3] + L[3].z * L[2];\n\t\tL[2] = -L[2].z * L[1] + L[1].z * L[2];\n\t} else if ( config == 12 ) {\n\t\tn = 4;\n\t\tL[1] = -L[1].z * L[2] + L[2].z * L[1];\n\t\tL[0] = -L[0].z * L[3] + L[3].z * L[0];\n\t} else if ( config == 13 ) {\n\t\tn = 5;\n\t\tL[4] = L[3];\n\t\tL[3] = L[2];\n\t\tL[2] = -L[1].z * L[2] + L[2].z * L[1];\n\t\tL[1] = -L[1].z * L[0] + L[0].z * L[1];\n\t} else if ( config == 14 ) {\n\t\tn = 5;\n\t\tL[4] = -L[0].z * L[3] + L[3].z * L[0];\n\t\tL[0] = -L[0].z * L[1] + L[1].z * L[0];\n\t} else if ( config == 15 ) {\n\t\tn = 4;\n\t}\n\tif ( n == 3 )\n\t\tL[3] = L[0];\n\tif ( n == 4 )\n\t\tL[4] = L[0];\n}\nfloat integrateLtcBrdfOverRectEdge( vec3 v1, vec3 v2 ) {\n\tfloat cosTheta = dot( v1, v2 );\n\tfloat theta = acos( cosTheta );\n\tfloat res = cross( v1, v2 ).z * ( ( theta > 0.001 ) ? theta / sin( theta ) : 1.0 );\n\treturn res;\n}\nvoid initRectPoints( const in vec3 pos, const in vec3 halfWidth, const in vec3 halfHeight, out vec3 rectPoints[4] ) {\n\trectPoints[0] = pos - halfWidth - halfHeight;\n\trectPoints[1] = pos + halfWidth - halfHeight;\n\trectPoints[2] = pos + halfWidth + halfHeight;\n\trectPoints[3] = pos - halfWidth + halfHeight;\n}\nvec3 integrateLtcBrdfOverRect( const in GeometricContext geometry, const in mat3 brdfMat, const in vec3 rectPoints[4] ) {\n\tvec3 N = geometry.normal;\n\tvec3 V = geometry.viewDir;\n\tvec3 P = geometry.position;\n\tvec3 T1, T2;\n\tT1 = normalize(V - N * dot( V, N ));\n\tT2 = - cross( N, T1 );\n\tmat3 brdfWrtSurface = brdfMat * transpose( mat3( T1, T2, N ) );\n\tvec3 clippedRect[5];\n\tclippedRect[0] = brdfWrtSurface * ( rectPoints[0] - P );\n\tclippedRect[1] = brdfWrtSurface * ( rectPoints[1] - P );\n\tclippedRect[2] = brdfWrtSurface * ( rectPoints[2] - P );\n\tclippedRect[3] = brdfWrtSurface * ( rectPoints[3] - P );\n\tint n;\n\tclipQuadToHorizon(clippedRect, n);\n\tif ( n == 0 )\n\t\treturn vec3( 0, 0, 0 );\n\tclippedRect[0] = normalize( clippedRect[0] );\n\tclippedRect[1] = normalize( clippedRect[1] );\n\tclippedRect[2] = normalize( clippedRect[2] );\n\tclippedRect[3] = normalize( clippedRect[3] );\n\tclippedRect[4] = normalize( clippedRect[4] );\n\tfloat sum = 0.0;\n\tsum += integrateLtcBrdfOverRectEdge( clippedRect[0], clippedRect[1] );\n\tsum += integrateLtcBrdfOverRectEdge( clippedRect[1], clippedRect[2] );\n\tsum += integrateLtcBrdfOverRectEdge( clippedRect[2], clippedRect[3] );\n\tif (n >= 4)\n\t\tsum += integrateLtcBrdfOverRectEdge( clippedRect[3], clippedRect[4] );\n\tif (n == 5)\n\t\tsum += integrateLtcBrdfOverRectEdge( clippedRect[4], clippedRect[0] );\n\tsum = max( 0.0, sum );\n\tvec3 Lo_i = vec3( sum, sum, sum );\n\treturn Lo_i/(2.0 * PI);\n}\nfloat ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length(f);\n\treturn max((l*l + f.z)/(l+1.0), 0.0);\n}\nvec3 EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot(v1, v2);\n\tfloat y = abs(x);\n\tfloat a = 0.86267 + (0.49788 + 0.01436*y)*y;\n\tfloat b = 3.45068 + (4.18814 + y)*y;\n\tfloat v = a/b;\n\tfloat theta_sintheta = (x > 0.0) ? v : 0.5*inversesqrt(1.0 - x*x) - v;\n\treturn cross(v1, v2)*theta_sintheta;\n}\nvec3 integrateLtcBrdfOverRectOptimized( const in GeometricContext geometry, const in mat3 brdfMat, const in vec3 rectPoints[4] ) {\n\tvec3 N = geometry.normal;\n\tvec3 V = geometry.viewDir;\n\tvec3 P = geometry.position;\n\tvec3 T1, T2;\n\tT1 = normalize(V - N * dot( V, N ));\n\tT2 = - cross( N, T1 );\n\tmat3 brdfWrtSurface = brdfMat * transpose( mat3( T1, T2, N ) );\n\tvec3 clippedRect[4];\n\tclippedRect[0] = brdfWrtSurface * ( rectPoints[0] - P );\n\tclippedRect[1] = brdfWrtSurface * ( rectPoints[1] - P );\n\tclippedRect[2] = brdfWrtSurface * ( rectPoints[2] - P );\n\tclippedRect[3] = brdfWrtSurface * ( rectPoints[3] - P );\n\tvec3 v1 = clippedRect[1] - clippedRect[0];\n\tvec3 v2 = clippedRect[3] - clippedRect[0];\n\tvec3 lightNormal = cross(v1, v2);\n\tbool bSameSide = dot(lightNormal, clippedRect[0]) > 0.0;\n\tif( !bSameSide )\n\t\treturn vec3(0.0);\n\tclippedRect[0] = normalize( clippedRect[0] );\n\tclippedRect[1] = normalize( clippedRect[1] );\n\tclippedRect[2] = normalize( clippedRect[2] );\n\tclippedRect[3] = normalize( clippedRect[3] );\n\tvec3 edgeVectorFormFactor = vec3(0.0);\n\tedgeVectorFormFactor += EdgeVectorFormFactor( clippedRect[0], clippedRect[1] );\n\tedgeVectorFormFactor += EdgeVectorFormFactor( clippedRect[1], clippedRect[2] );\n\tedgeVectorFormFactor += EdgeVectorFormFactor( clippedRect[2], clippedRect[3] );\n\tedgeVectorFormFactor += EdgeVectorFormFactor( clippedRect[3], clippedRect[0] );\n\tvec3 Lo_i = vec3( ClippedSphereFormFactor( edgeVectorFormFactor ) );\n\treturn Lo_i;\n}\nvec3 Rect_Area_Light_Specular_Reflectance(\n\t\tconst in GeometricContext geometry,\n\t\tconst in vec3 lightPos, const in vec3 lightHalfWidth, const in vec3 lightHalfHeight,\n\t\tconst in float roughness,\n\t\tconst in sampler2D ltcMat, const in sampler2D ltcMag ) {\n\tvec3 rectPoints[4];\n\tinitRectPoints( lightPos, lightHalfWidth, lightHalfHeight, rectPoints );\n\tvec2 uv = ltcTextureCoords( geometry, roughness );\n\tvec4 brdfLtcApproxParams, t;\n\tbrdfLtcApproxParams = texture2D( ltcMat, uv );\n\tt = texture2D( ltcMat, uv );\n\tfloat brdfLtcScalar = texture2D( ltcMag, uv ).a;\n\tmat3 brdfLtcApproxMat = mat3(\n\t\tvec3( 1, 0, t.y ),\n\t\tvec3( 0, t.z, 0 ),\n\t\tvec3( t.w, 0, t.x )\n\t);\n\tvec3 specularReflectance = integrateLtcBrdfOverRectOptimized( geometry, brdfLtcApproxMat, rectPoints );\n\tspecularReflectance *= brdfLtcScalar;\n\treturn specularReflectance;\n}\nvec3 Rect_Area_Light_Diffuse_Reflectance(\n\t\tconst in GeometricContext geometry,\n\t\tconst in vec3 lightPos, const in vec3 lightHalfWidth, const in vec3 lightHalfHeight ) {\n\tvec3 rectPoints[4];\n\tinitRectPoints( lightPos, lightHalfWidth, lightHalfHeight, rectPoints );\n\tmat3 diffuseBrdfMat = mat3(1);\n\tvec3 diffuseReflectance = integrateLtcBrdfOverRectOptimized( geometry, diffuseBrdfMat, rectPoints );\n\treturn diffuseReflectance;\n}\nvec3 BRDF_Specular_GGX_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n\treturn specularColor * AB.x + AB.y;\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\n}\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\n\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\n}\n"; + + var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\t\tvec3 vSigmaX = dFdx( surf_pos );\n\t\tvec3 vSigmaY = dFdy( surf_pos );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 );\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif\n"; + + var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; ++ i ) {\n\t\tvec4 plane = clippingPlanes[ i ];\n\t\tif ( dot( vViewPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t\t\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; ++ i ) {\n\t\t\tvec4 plane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vViewPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\tif ( clipped ) discard;\n\t\n\t#endif\n#endif\n"; + + var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\t#if ! defined( PHYSICAL ) && ! defined( PHONG )\n\t\tvarying vec3 vViewPosition;\n\t#endif\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif\n"; + + var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvarying vec3 vViewPosition;\n#endif\n"; + + var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n"; + + var color_fragment = "#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif"; + + var color_pars_fragment = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif\n"; + + var color_pars_vertex = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif"; + + var color_vertex = "#ifdef USE_COLOR\n\tvColor.xyz = color.xyz;\n#endif"; + + var common = "#define PI 3.14159265359\n#define PI2 6.28318530718\n#define PI_HALF 1.5707963267949\n#define RECIPROCAL_PI 0.31830988618\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.442695\n#define EPSILON 1e-6\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#define whiteCompliment(a) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract(sin(sn) * c);\n}\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\tfloat distance = dot( planeNormal, point - pointOnPlane );\n\treturn - distance * planeNormal + point;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\n}\nmat3 transpose( const in mat3 v ) {\n\tmat3 tmp;\n\ttmp[0] = vec3(v[0].x, v[1].x, v[2].x);\n\ttmp[1] = vec3(v[0].y, v[1].y, v[2].y);\n\ttmp[2] = vec3(v[0].z, v[1].z, v[2].z);\n\treturn tmp;\n}\n"; + + var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n#define cubeUV_textureSize (1024.0)\nint getFaceFromDirection(vec3 direction) {\n\tvec3 absDirection = abs(direction);\n\tint face = -1;\n\tif( absDirection.x > absDirection.z ) {\n\t\tif(absDirection.x > absDirection.y )\n\t\t\tface = direction.x > 0.0 ? 0 : 3;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\telse {\n\t\tif(absDirection.z > absDirection.y )\n\t\t\tface = direction.z > 0.0 ? 2 : 5;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\treturn face;\n}\n#define cubeUV_maxLods1 (log2(cubeUV_textureSize*0.25) - 1.0)\n#define cubeUV_rangeClamp (exp2((6.0 - 1.0) * 2.0))\nvec2 MipLevelInfo( vec3 vec, float roughnessLevel, float roughness ) {\n\tfloat scale = exp2(cubeUV_maxLods1 - roughnessLevel);\n\tfloat dxRoughness = dFdx(roughness);\n\tfloat dyRoughness = dFdy(roughness);\n\tvec3 dx = dFdx( vec * scale * dxRoughness );\n\tvec3 dy = dFdy( vec * scale * dyRoughness );\n\tfloat d = max( dot( dx, dx ), dot( dy, dy ) );\n\td = clamp(d, 1.0, cubeUV_rangeClamp);\n\tfloat mipLevel = 0.5 * log2(d);\n\treturn vec2(floor(mipLevel), fract(mipLevel));\n}\n#define cubeUV_maxLods2 (log2(cubeUV_textureSize*0.25) - 2.0)\n#define cubeUV_rcpTextureSize (1.0 / cubeUV_textureSize)\nvec2 getCubeUV(vec3 direction, float roughnessLevel, float mipLevel) {\n\tmipLevel = roughnessLevel > cubeUV_maxLods2 - 3.0 ? 0.0 : mipLevel;\n\tfloat a = 16.0 * cubeUV_rcpTextureSize;\n\tvec2 exp2_packed = exp2( vec2( roughnessLevel, mipLevel ) );\n\tvec2 rcp_exp2_packed = vec2( 1.0 ) / exp2_packed;\n\tfloat powScale = exp2_packed.x * exp2_packed.y;\n\tfloat scale = rcp_exp2_packed.x * rcp_exp2_packed.y * 0.25;\n\tfloat mipOffset = 0.75*(1.0 - rcp_exp2_packed.y) * rcp_exp2_packed.x;\n\tbool bRes = mipLevel == 0.0;\n\tscale = bRes && (scale < a) ? a : scale;\n\tvec3 r;\n\tvec2 offset;\n\tint face = getFaceFromDirection(direction);\n\tfloat rcpPowScale = 1.0 / powScale;\n\tif( face == 0) {\n\t\tr = vec3(direction.x, -direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 1) {\n\t\tr = vec3(direction.y, direction.x, direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 2) {\n\t\tr = vec3(direction.z, direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 3) {\n\t\tr = vec3(direction.x, direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse if( face == 4) {\n\t\tr = vec3(direction.y, direction.x, -direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse {\n\t\tr = vec3(direction.z, -direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\tr = normalize(r);\n\tfloat texelOffset = 0.5 * cubeUV_rcpTextureSize;\n\tvec2 s = ( r.yz / abs( r.x ) + vec2( 1.0 ) ) * 0.5;\n\tvec2 base = offset + vec2( texelOffset );\n\treturn base + s * ( scale - 2.0 * texelOffset );\n}\n#define cubeUV_maxLods3 (log2(cubeUV_textureSize*0.25) - 3.0)\nvec4 textureCubeUV(vec3 reflectedDirection, float roughness ) {\n\tfloat roughnessVal = roughness* cubeUV_maxLods3;\n\tfloat r1 = floor(roughnessVal);\n\tfloat r2 = r1 + 1.0;\n\tfloat t = fract(roughnessVal);\n\tvec2 mipInfo = MipLevelInfo(reflectedDirection, r1, roughness);\n\tfloat s = mipInfo.y;\n\tfloat level0 = mipInfo.x;\n\tfloat level1 = level0 + 1.0;\n\tlevel1 = level1 > 5.0 ? 5.0 : level1;\n\tlevel0 += min( floor( s + 0.5 ), 5.0 );\n\tvec2 uv_10 = getCubeUV(reflectedDirection, r1, level0);\n\tvec4 color10 = envMapTexelToLinear(texture2D(envMap, uv_10));\n\tvec2 uv_20 = getCubeUV(reflectedDirection, r2, level0);\n\tvec4 color20 = envMapTexelToLinear(texture2D(envMap, uv_20));\n\tvec4 result = mix(color10, color20, t);\n\treturn vec4(result.rgb, 1.0);\n}\n#endif\n"; + + var defaultnormal_vertex = "#ifdef FLIP_SIDED\n\tobjectNormal = -objectNormal;\n#endif\nvec3 transformedNormal = normalMatrix * objectNormal;\n"; + + var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif\n"; + + var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normal * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );\n#endif\n"; + + var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif\n"; + + var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif\n"; + + var encodings_fragment = " gl_FragColor = linearToOutputTexel( gl_FragColor );\n"; + + var encodings_pars_fragment = "\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );\n}\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );\n}\nvec4 sRGBToLinear( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.w );\n}\nvec4 RGBEToLinear( in vec4 value ) {\n\treturn vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );\n}\nvec4 LinearToRGBE( in vec4 value ) {\n\tfloat maxComponent = max( max( value.r, value.g ), value.b );\n\tfloat fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );\n\treturn vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );\n}\nvec4 RGBMToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.xyz * value.w * maxRange, 1.0 );\n}\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\n\tfloat M = clamp( maxRGB / maxRange, 0.0, 1.0 );\n\tM = ceil( M * 255.0 ) / 255.0;\n\treturn vec4( value.rgb / ( M * maxRange ), M );\n}\nvec4 RGBDToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );\n}\nvec4 LinearToRGBD( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\n\tfloat D = max( maxRange / maxRGB, 1.0 );\n\tD = min( floor( D ) / 255.0, 1.0 );\n\treturn vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\n}\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\nvec4 LinearToLogLuv( in vec4 value ) {\n\tvec3 Xp_Y_XYZp = value.rgb * cLogLuvM;\n\tXp_Y_XYZp = max(Xp_Y_XYZp, vec3(1e-6, 1e-6, 1e-6));\n\tvec4 vResult;\n\tvResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\n\tfloat Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\n\tvResult.w = fract(Le);\n\tvResult.z = (Le - (floor(vResult.w*255.0))/255.0)/255.0;\n\treturn vResult;\n}\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\nvec4 LogLuvToLinear( in vec4 value ) {\n\tfloat Le = value.z * 255.0 + value.w;\n\tvec3 Xp_Y_XYZp;\n\tXp_Y_XYZp.y = exp2((Le - 127.0) / 2.0);\n\tXp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\n\tXp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\n\tvec3 vRGB = Xp_Y_XYZp.rgb * cLogLuvInverseM;\n\treturn vec4( max(vRGB, 0.0), 1.0 );\n}\n"; + + var envmap_fragment = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\tvec2 sampleUV;\n\t\tsampleUV.y = saturate( flipNormal * reflectVec.y * 0.5 + 0.5 );\n\t\tsampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\n\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\tvec3 reflectView = flipNormal * normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) );\n\t\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\tenvColor = envMapTexelToLinear( envColor );\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif\n"; + + var envmap_pars_fragment = "#if defined( USE_ENVMAP ) || defined( PHYSICAL )\n\tuniform float reflectivity;\n\tuniform float envMapIntensity;\n#endif\n#ifdef USE_ENVMAP\n\t#if ! defined( PHYSICAL ) && ( defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) )\n\t\tvarying vec3 vWorldPosition;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\tuniform float flipEnvMap;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( PHYSICAL )\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif\n"; + + var envmap_pars_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif\n"; + + var envmap_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif\n"; + + var fog_vertex = "\n#ifdef USE_FOG\nfogDepth = -mvPosition.z;\n#endif"; + + var fog_pars_vertex = "#ifdef USE_FOG\n varying float fogDepth;\n#endif\n"; + + var fog_fragment = "#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 ) );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, fogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif\n"; + + var fog_pars_fragment = "#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float fogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif\n"; + + var gradientmap_pars_fragment = "#ifdef TOON\n\tuniform sampler2D gradientMap;\n\tvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\t\tfloat dotNL = dot( normal, lightDirection );\n\t\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t\t#ifdef USE_GRADIENTMAP\n\t\t\treturn texture2D( gradientMap, coord ).rgb;\n\t\t#else\n\t\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\n\t\t#endif\n\t}\n#endif\n"; + + var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\treflectedLight.indirectDiffuse += PI * texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n#endif\n"; + + var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif"; + + var lights_lambert_vertex = "vec3 diffuse = vec3( 1.0 );\nGeometricContext geometry;\ngeometry.position = mvPosition.xyz;\ngeometry.normal = normalize( transformedNormal );\ngeometry.viewDir = normalize( -mvPosition.xyz );\nGeometricContext backGeometry;\nbackGeometry.position = geometry.position;\nbackGeometry.normal = -geometry.normal;\nbackGeometry.viewDir = geometry.viewDir;\nvLightFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\n\tvLightBack = vec3( 0.0 );\n#endif\nIncidentLight directLight;\nfloat dotNL;\nvec3 directLightColor_Diffuse;\n#if NUM_POINT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tgetPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tgetSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_DIR_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tgetDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\tvLightFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\n\t\t#endif\n\t}\n#endif\n"; + + var lights_pars = "uniform vec3 ambientLightColor;\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treturn irradiance;\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tdirectLight.color = directionalLight.color;\n\t\tdirectLight.direction = directionalLight.direction;\n\t\tdirectLight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tdirectLight.color = pointLight.color;\n\t\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );\n\t\tdirectLight.visible = ( directLight.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tfloat angleCos = dot( directLight.direction, spotLight.direction );\n\t\tif ( angleCos > spotLight.coneCos ) {\n\t\t\tfloat spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\t\tdirectLight.color = spotLight.color;\n\t\t\tdirectLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tdirectLight.visible = true;\n\t\t} else {\n\t\t\tdirectLight.color = vec3( 0.0 );\n\t\t\tdirectLight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltcMat;\tuniform sampler2D ltcMag;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) {\n\t\tfloat dotNL = dot( geometry.normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tirradiance *= PI;\n\t\t#endif\n\t\treturn irradiance;\n\t}\n#endif\n#if defined( USE_ENVMAP ) && defined( PHYSICAL )\n\tvec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {\n\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\tvec4 envMapColor = textureCubeUV( queryVec, 1.0 );\n\t\t#else\n\t\t\tvec4 envMapColor = vec4( 0.0 );\n\t\t#endif\n\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t}\n\tfloat getSpecularMIPLevel( const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar - 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\n\t}\n\tvec3 getLightProbeIndirectRadiance( const in GeometricContext geometry, const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( -geometry.viewDir, geometry.normal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( -geometry.viewDir, geometry.normal, refractionRatio );\n\t\t#endif\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( blinnShininessExponent, maxMIPLevel );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\tvec4 envMapColor = textureCubeUV(queryReflectVec, BlinnExponentToGGXRoughness(blinnShininessExponent));\n\t\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\t\tvec2 sampleUV;\n\t\t\tsampleUV.y = saturate( reflectVec.y * 0.5 + 0.5 );\n\t\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, sampleUV, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, sampleUV, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0,0.0,1.0 ) );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#endif\n\t\treturn envMapColor.rgb * envMapIntensity;\n\t}\n#endif\n"; + + var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;\n"; + + var lights_phong_pars_fragment = "varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct BlinnPhongMaterial {\n\tvec3\tdiffuseColor;\n\tvec3\tspecularColor;\n\tfloat\tspecularShininess;\n\tfloat\tspecularStrength;\n};\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_BlinnPhong( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 matDiffColor = material.diffuseColor;\n\t\tvec3 matSpecColor = material.specularColor;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = BlinnExponentToGGXRoughness( material.specularShininess );\n\t\tvec3 spec = Rect_Area_Light_Specular_Reflectance(\n\t\t\t\tgeometry,\n\t\t\t\trectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight,\n\t\t\t\troughness,\n\t\t\t\tltcMat, ltcMag );\n\t\tvec3 diff = Rect_Area_Light_Diffuse_Reflectance(\n\t\t\t\tgeometry,\n\t\t\t\trectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight );\n\t\treflectedLight.directSpecular += lightColor * matSpecColor * spec;\n\t\treflectedLight.directDiffuse += lightColor * matDiffColor * diff;\n\t}\n#endif\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifdef TOON\n\t\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\t#else\n\t\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\t\tvec3 irradiance = dotNL * directLight.color;\n\t#endif\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)\n"; + + var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nmaterial.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );\n#ifdef STANDARD\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.clearCoat = saturate( clearCoat );\tmaterial.clearCoatRoughness = clamp( clearCoatRoughness, 0.04, 1.0 );\n#endif\n"; + + var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3\tdiffuseColor;\n\tfloat\tspecularRoughness;\n\tvec3\tspecularColor;\n\t#ifndef STANDARD\n\t\tfloat clearCoat;\n\t\tfloat clearCoatRoughness;\n\t#endif\n};\n#define MAXIMUM_SPECULAR_COEFFICIENT 0.16\n#define DEFAULT_SPECULAR_COEFFICIENT 0.04\nfloat clearCoatDHRApprox( const in float roughness, const in float dotNL ) {\n\treturn DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 matDiffColor = material.diffuseColor;\n\t\tvec3 matSpecColor = material.specularColor;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.specularRoughness;\n\t\tvec3 spec = Rect_Area_Light_Specular_Reflectance(\n\t\t\t\tgeometry,\n\t\t\t\trectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight,\n\t\t\t\troughness,\n\t\t\t\tltcMat, ltcMag );\n\t\tvec3 diff = Rect_Area_Light_Diffuse_Reflectance(\n\t\t\t\tgeometry,\n\t\t\t\trectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight );\n\t\treflectedLight.directSpecular += lightColor * matSpecColor * spec;\n\t\treflectedLight.directDiffuse += lightColor * matDiffColor * diff;\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\t#ifndef STANDARD\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry, material.specularColor, material.specularRoughness );\n\treflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\t#ifndef STANDARD\n\t\treflectedLight.directSpecular += irradiance * material.clearCoat * BRDF_Specular_GGX( directLight, geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 clearCoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifndef STANDARD\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\tfloat dotNL = dotNV;\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.indirectSpecular += ( 1.0 - clearCoatDHR ) * radiance * BRDF_Specular_GGX_Environment( geometry, material.specularColor, material.specularRoughness );\n\t#ifndef STANDARD\n\t\treflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * BRDF_Specular_GGX_Environment( geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\n#define Material_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.specularRoughness )\n#define Material_ClearCoat_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.clearCoatRoughness )\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}\n"; + + var lights_template = "\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = normalize( vViewPosition );\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( pointLight.shadow, directLight.visible ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( directionalLight.shadow, directLight.visible ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#ifdef USE_LIGHTMAP\n\t\tvec3 lightMapIrradiance = texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tlightMapIrradiance *= PI;\n\t\t#endif\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t}\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tirradiance += getLightProbeIndirectIrradiance( geometry, 8 );\n\t#endif\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tvec3 radiance = getLightProbeIndirectRadiance( geometry, Material_BlinnShininessExponent( material ), 8 );\n\t#ifndef STANDARD\n\t\tvec3 clearCoatRadiance = getLightProbeIndirectRadiance( geometry, Material_ClearCoat_BlinnShininessExponent( material ), 8 );\n\t#else\n\t\tvec3 clearCoatRadiance = vec3( 0.0 );\n\t#endif\n\tRE_IndirectSpecular( radiance, clearCoatRadiance, geometry, material, reflectedLight );\n#endif\n"; + + var logdepthbuf_fragment = "#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)\n\tgl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;\n#endif"; + + var logdepthbuf_pars_fragment = "#ifdef USE_LOGDEPTHBUF\n\tuniform float logDepthBufFC;\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#endif\n#endif\n"; + + var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#endif\n\tuniform float logDepthBufFC;\n#endif"; + + var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\tgl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC;\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t#else\n\t\tgl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;\n\t#endif\n#endif\n"; + + var map_fragment = "#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif\n"; + + var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n"; + + var map_particle_fragment = "#ifdef USE_MAP\n\tvec4 mapTexel = texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\n#endif\n"; + + var map_particle_pars_fragment = "#ifdef USE_MAP\n\tuniform vec4 offsetRepeat;\n\tuniform sampler2D map;\n#endif\n"; + + var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif\n"; + + var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif"; + + var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\n\tobjectNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\n\tobjectNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\n\tobjectNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\n#endif\n"; + + var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\t#ifndef USE_MORPHNORMALS\n\tuniform float morphTargetInfluences[ 8 ];\n\t#else\n\tuniform float morphTargetInfluences[ 4 ];\n\t#endif\n#endif"; + + var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\n\ttransformed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\n\ttransformed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\n\ttransformed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n\t#ifndef USE_MORPHNORMALS\n\ttransformed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\n\ttransformed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\n\ttransformed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\n\ttransformed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n\t#endif\n#endif\n"; + + var normal_flip = "#ifdef DOUBLE_SIDED\n\tfloat flipNormal = ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n#else\n\tfloat flipNormal = 1.0;\n#endif\n"; + + var normal_fragment = "#ifdef FLAT_SHADED\n\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\n\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal ) * flipNormal;\n#endif\n#ifdef USE_NORMALMAP\n\tnormal = perturbNormal2Arb( -vViewPosition, normal );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif\n"; + + var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tvec3 S = normalize( q0 * st1.t - q1 * st0.t );\n\t\tvec3 T = normalize( -q0 * st1.s + q1 * st0.s );\n\t\tvec3 N = normalize( surf_norm );\n\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\tmapN.xy = normalScale * mapN.xy;\n\t\tmat3 tsn = mat3( S, T, N );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif\n"; + + var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 1.0 - 2.0 * rgb.xyz;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn (( near + viewZ ) * far ) / (( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}\n"; + + var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif\n"; + + var project_vertex = "#ifdef USE_SKINNING\n\tvec4 mvPosition = modelViewMatrix * skinned;\n#else\n\tvec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\n#endif\ngl_Position = projectionMatrix * mvPosition;\n"; + + var dithering_fragment = "#if defined( DITHERING )\n gl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif\n"; + + var dithering_pars_fragment = "#if defined( DITHERING )\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif\n"; + + var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif\n"; + + var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif"; + + var shadowmap_pars_fragment = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tfloat texture2DShadowLerp( sampler2D depths, vec2 size, vec2 uv, float compare ) {\n\t\tconst vec2 offset = vec2( 0.0, 1.0 );\n\t\tvec2 texelSize = vec2( 1.0 ) / size;\n\t\tvec2 centroidUV = floor( uv * size + 0.5 ) / size;\n\t\tfloat lb = texture2DCompare( depths, centroidUV + texelSize * offset.xx, compare );\n\t\tfloat lt = texture2DCompare( depths, centroidUV + texelSize * offset.xy, compare );\n\t\tfloat rb = texture2DCompare( depths, centroidUV + texelSize * offset.yx, compare );\n\t\tfloat rt = texture2DCompare( depths, centroidUV + texelSize * offset.yy, compare );\n\t\tvec2 f = fract( uv * size + 0.5 );\n\t\tfloat a = mix( lb, lt, f.y );\n\t\tfloat b = mix( rb, rt, f.y );\n\t\tfloat c = mix( a, b, f.x );\n\t\treturn c;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\treturn (\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn 1.0;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\tfloat dp = ( length( lightToPosition ) - shadowBias ) / 1000.0;\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif\n"; + + var shadowmap_pars_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n#endif\n"; + + var shadowmap_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n#endif\n"; + + var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\tDirectionalLight directionalLight;\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tshadow *= bool( directionalLight.shadow ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\tSpotLight spotLight;\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tshadow *= bool( spotLight.shadow ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\tPointLight pointLight;\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tshadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#endif\n\treturn shadow;\n}\n"; + + var skinbase_vertex = "#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif"; + + var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\t#ifdef BONE_TEXTURE\n\t\tuniform sampler2D boneTexture;\n\t\tuniform int boneTextureSize;\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tfloat j = i * 4.0;\n\t\t\tfloat x = mod( j, float( boneTextureSize ) );\n\t\t\tfloat y = floor( j / float( boneTextureSize ) );\n\t\t\tfloat dx = 1.0 / float( boneTextureSize );\n\t\t\tfloat dy = 1.0 / float( boneTextureSize );\n\t\t\ty = dy * ( y + 0.5 );\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\t\treturn bone;\n\t\t}\n\t#else\n\t\tuniform mat4 boneMatrices[ MAX_BONES ];\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tmat4 bone = boneMatrices[ int(i) ];\n\t\t\treturn bone;\n\t\t}\n\t#endif\n#endif\n"; + + var skinning_vertex = "#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\tskinned = bindMatrixInverse * skinned;\n#endif\n"; + + var skinnormal_vertex = "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n#endif\n"; + + var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif"; + + var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif"; + + var tonemapping_fragment = "#if defined( TONE_MAPPING )\n gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif\n"; + + var tonemapping_pars_fragment = "#define saturate(a) clamp( a, 0.0, 1.0 )\nuniform float toneMappingExposure;\nuniform float toneMappingWhitePoint;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\n#define Uncharted2Helper( x ) max( ( ( x * ( 0.15 * x + 0.10 * 0.50 ) + 0.20 * 0.02 ) / ( x * ( 0.15 * x + 0.50 ) + 0.20 * 0.30 ) ) - 0.02 / 0.30, vec3( 0.0 ) )\nvec3 Uncharted2ToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\n"; + + var uv_pars_fragment = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n#endif"; + + var uv_pars_vertex = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n\tuniform vec4 offsetRepeat;\n#endif\n"; + + var uv_vertex = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvUv = uv * offsetRepeat.zw + offsetRepeat.xy;\n#endif"; + + var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif"; + + var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n#endif"; + + var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = uv2;\n#endif"; + + var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( PHYSICAL ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )\n\t#ifdef USE_SKINNING\n\t\tvec4 worldPosition = modelMatrix * skinned;\n\t#else\n\t\tvec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\n\t#endif\n#endif\n"; + + var cube_frag = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldPosition;\n#include \nvoid main() {\n\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\n\tgl_FragColor.a *= opacity;\n}\n"; + + var cube_vert = "varying vec3 vWorldPosition;\n#include \nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}\n"; + + var depth_frag = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( gl_FragCoord.z ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( gl_FragCoord.z );\n\t#endif\n}\n"; + + var depth_vert = "#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + + var distanceRGBA_frag = "uniform vec3 lightPos;\nvarying vec4 vWorldPosition;\n#include \n#include \n#include \nvoid main () {\n\t#include \n\tgl_FragColor = packDepthToRGBA( length( vWorldPosition.xyz - lightPos.xyz ) / 1000.0 );\n}\n"; + + var distanceRGBA_vert = "varying vec4 vWorldPosition;\n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition;\n}\n"; + + var equirect_frag = "uniform sampler2D tEquirect;\nuniform float tFlip;\nvarying vec3 vWorldPosition;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldPosition );\n\tvec2 sampleUV;\n\tsampleUV.y = saturate( tFlip * direction.y * -0.5 + 0.5 );\n\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n}\n"; + + var equirect_vert = "varying vec3 vWorldPosition;\n#include \nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}\n"; + + var linedashed_frag = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + + var linedashed_vert = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvLineDistance = scale * lineDistance;\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}\n"; + + var meshbasic_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\treflectedLight.indirectDiffuse += texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + + var meshbasic_vert = "#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#ifdef USE_ENVMAP\n\t#include \n\t#include \n\t#include \n\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + + var meshlambert_frag = "uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\treflectedLight.indirectDiffuse = getAmbientLightIrradiance( ambientLightColor );\n\t#include \n\treflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\n\t#else\n\t\treflectedLight.directDiffuse = vLightFront;\n\t#endif\n\treflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();\n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + + var meshlambert_vert = "#define LAMBERT\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + + var meshphong_frag = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + + var meshphong_vert = "#define PHONG\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + + var meshphysical_frag = "#define PHYSICAL\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifndef STANDARD\n\tuniform float clearCoat;\n\tuniform float clearCoatRoughness;\n#endif\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + + var meshphysical_vert = "#define PHYSICAL\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}\n"; + + var normal_frag = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n}\n"; + + var normal_vert = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}\n"; + + var points_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + + var points_vert = "uniform float size;\nuniform float scale;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#ifdef USE_SIZEATTENUATION\n\t\tgl_PointSize = size * ( scale / - mvPosition.z );\n\t#else\n\t\tgl_PointSize = size;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + + var shadow_frag = "uniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tgl_FragColor = vec4( 0.0, 0.0, 0.0, opacity * ( 1.0 - getShadowMask() ) );\n}\n"; + + var shadow_vert = "#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + + var ShaderChunk = { + alphamap_fragment: alphamap_fragment, + alphamap_pars_fragment: alphamap_pars_fragment, + alphatest_fragment: alphatest_fragment, + aomap_fragment: aomap_fragment, + aomap_pars_fragment: aomap_pars_fragment, + begin_vertex: begin_vertex, + beginnormal_vertex: beginnormal_vertex, + bsdfs: bsdfs, + bumpmap_pars_fragment: bumpmap_pars_fragment, + clipping_planes_fragment: clipping_planes_fragment, + clipping_planes_pars_fragment: clipping_planes_pars_fragment, + clipping_planes_pars_vertex: clipping_planes_pars_vertex, + clipping_planes_vertex: clipping_planes_vertex, + color_fragment: color_fragment, + color_pars_fragment: color_pars_fragment, + color_pars_vertex: color_pars_vertex, + color_vertex: color_vertex, + common: common, + cube_uv_reflection_fragment: cube_uv_reflection_fragment, + defaultnormal_vertex: defaultnormal_vertex, + displacementmap_pars_vertex: displacementmap_pars_vertex, + displacementmap_vertex: displacementmap_vertex, + emissivemap_fragment: emissivemap_fragment, + emissivemap_pars_fragment: emissivemap_pars_fragment, + encodings_fragment: encodings_fragment, + encodings_pars_fragment: encodings_pars_fragment, + envmap_fragment: envmap_fragment, + envmap_pars_fragment: envmap_pars_fragment, + envmap_pars_vertex: envmap_pars_vertex, + envmap_vertex: envmap_vertex, + fog_vertex: fog_vertex, + fog_pars_vertex: fog_pars_vertex, + fog_fragment: fog_fragment, + fog_pars_fragment: fog_pars_fragment, + gradientmap_pars_fragment: gradientmap_pars_fragment, + lightmap_fragment: lightmap_fragment, + lightmap_pars_fragment: lightmap_pars_fragment, + lights_lambert_vertex: lights_lambert_vertex, + lights_pars: lights_pars, + lights_phong_fragment: lights_phong_fragment, + lights_phong_pars_fragment: lights_phong_pars_fragment, + lights_physical_fragment: lights_physical_fragment, + lights_physical_pars_fragment: lights_physical_pars_fragment, + lights_template: lights_template, + logdepthbuf_fragment: logdepthbuf_fragment, + logdepthbuf_pars_fragment: logdepthbuf_pars_fragment, + logdepthbuf_pars_vertex: logdepthbuf_pars_vertex, + logdepthbuf_vertex: logdepthbuf_vertex, + map_fragment: map_fragment, + map_pars_fragment: map_pars_fragment, + map_particle_fragment: map_particle_fragment, + map_particle_pars_fragment: map_particle_pars_fragment, + metalnessmap_fragment: metalnessmap_fragment, + metalnessmap_pars_fragment: metalnessmap_pars_fragment, + morphnormal_vertex: morphnormal_vertex, + morphtarget_pars_vertex: morphtarget_pars_vertex, + morphtarget_vertex: morphtarget_vertex, + normal_flip: normal_flip, + normal_fragment: normal_fragment, + normalmap_pars_fragment: normalmap_pars_fragment, + packing: packing, + premultiplied_alpha_fragment: premultiplied_alpha_fragment, + project_vertex: project_vertex, + dithering_fragment: dithering_fragment, + dithering_pars_fragment: dithering_pars_fragment, + roughnessmap_fragment: roughnessmap_fragment, + roughnessmap_pars_fragment: roughnessmap_pars_fragment, + shadowmap_pars_fragment: shadowmap_pars_fragment, + shadowmap_pars_vertex: shadowmap_pars_vertex, + shadowmap_vertex: shadowmap_vertex, + shadowmask_pars_fragment: shadowmask_pars_fragment, + skinbase_vertex: skinbase_vertex, + skinning_pars_vertex: skinning_pars_vertex, + skinning_vertex: skinning_vertex, + skinnormal_vertex: skinnormal_vertex, + specularmap_fragment: specularmap_fragment, + specularmap_pars_fragment: specularmap_pars_fragment, + tonemapping_fragment: tonemapping_fragment, + tonemapping_pars_fragment: tonemapping_pars_fragment, + uv_pars_fragment: uv_pars_fragment, + uv_pars_vertex: uv_pars_vertex, + uv_vertex: uv_vertex, + uv2_pars_fragment: uv2_pars_fragment, + uv2_pars_vertex: uv2_pars_vertex, + uv2_vertex: uv2_vertex, + worldpos_vertex: worldpos_vertex, + + cube_frag: cube_frag, + cube_vert: cube_vert, + depth_frag: depth_frag, + depth_vert: depth_vert, + distanceRGBA_frag: distanceRGBA_frag, + distanceRGBA_vert: distanceRGBA_vert, + equirect_frag: equirect_frag, + equirect_vert: equirect_vert, + linedashed_frag: linedashed_frag, + linedashed_vert: linedashed_vert, + meshbasic_frag: meshbasic_frag, + meshbasic_vert: meshbasic_vert, + meshlambert_frag: meshlambert_frag, + meshlambert_vert: meshlambert_vert, + meshphong_frag: meshphong_frag, + meshphong_vert: meshphong_vert, + meshphysical_frag: meshphysical_frag, + meshphysical_vert: meshphysical_vert, + normal_frag: normal_frag, + normal_vert: normal_vert, + points_frag: points_frag, + points_vert: points_vert, + shadow_frag: shadow_frag, + shadow_vert: shadow_vert + }; + /** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ @@ -6035,7 +5996,7 @@ { emissive: { value: new Color( 0x000000 ) }, roughness: { value: 0.5 }, - metalness: { value: 0 }, + metalness: { value: 0.5 }, envMapIntensity: { value: 1 } // temporary } ] ), @@ -6175,9 +6136,7 @@ } - Box2.prototype = { - - constructor: Box2, + Object.assign( Box2.prototype, { set: function ( min, max ) { @@ -6321,7 +6280,8 @@ intersectsBox: function ( box ) { - // using 6 splitting planes to rule out intersections. + // using 4 splitting planes to rule out intersections + return box.max.x < this.min.x || box.min.x > this.max.x || box.max.y < this.min.y || box.min.y > this.max.y ? false : true; @@ -6380,7 +6340,7 @@ } - }; + } ); /** * @author mikael emtinger / http://gomo.se/ @@ -6608,7 +6568,7 @@ gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); state.disable( gl.CULL_FACE ); - state.setDepthWrite( false ); + state.buffers.depth.setMask( false ); for ( var i = 0, l = flares.length; i < l; i ++ ) { @@ -6733,7 +6693,7 @@ state.enable( gl.CULL_FACE ); state.enable( gl.DEPTH_TEST ); - state.setDepthWrite( true ); + state.buffers.depth.setMask( true ); renderer.resetGLState(); @@ -6987,8 +6947,8 @@ gl.uniform2fv( uniforms.scale, scale ); state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); - state.setDepthTest( material.depthTest ); - state.setDepthWrite( material.depthWrite ); + state.buffers.depth.setTest( material.depthTest ); + state.buffers.depth.setMask( material.depthWrite ); if ( material.map ) { @@ -7189,6 +7149,8 @@ this.polygonOffsetFactor = 0; this.polygonOffsetUnits = 0; + this.dithering = false; + this.alphaTest = 0; this.premultipliedAlpha = false; @@ -7196,29 +7158,14 @@ this.visible = true; - this._needsUpdate = true; + this.needsUpdate = true; } - Material.prototype = { - - constructor: Material, + Object.assign( Material.prototype, EventDispatcher.prototype, { isMaterial: true, - get needsUpdate() { - - return this._needsUpdate; - - }, - - set needsUpdate( value ) { - - if ( value === true ) this.update(); - this._needsUpdate = value; - - }, - setValues: function ( values ) { if ( values === undefined ) return; @@ -7281,7 +7228,7 @@ var data = { metadata: { - version: 4.4, + version: 4.5, type: 'Material', generator: 'Material.toJSON' } @@ -7370,6 +7317,8 @@ data.skinning = this.skinning; data.morphTargets = this.morphTargets; + data.dithering = this.dithering; + // TODO: Copied from Object3D.toJSON function extractFromCache( cache ) { @@ -7442,6 +7391,8 @@ this.polygonOffsetFactor = source.polygonOffsetFactor; this.polygonOffsetUnits = source.polygonOffsetUnits; + this.dithering = source.dithering; + this.alphaTest = source.alphaTest; this.premultipliedAlpha = source.premultipliedAlpha; @@ -7471,21 +7422,13 @@ }, - update: function () { - - this.dispatchEvent( { type: 'update' } ); - - }, - dispose: function () { this.dispatchEvent( { type: 'dispose' } ); } - }; - - Object.assign( Material.prototype, EventDispatcher.prototype ); + } ); /** * @author alteredq / http://alteredqualia.com/ @@ -7702,9 +7645,7 @@ } - Box3.prototype = { - - constructor: Box3, + Object.assign( Box3.prototype, { isBox3: true, @@ -7999,12 +7940,10 @@ intersectsSphere: ( function () { - var closestPoint; + var closestPoint = new Vector3(); return function intersectsSphere( sphere ) { - if ( closestPoint === undefined ) closestPoint = new Vector3(); - // Find the point on the AABB closest to the sphere center. this.clampPoint( sphere.center, closestPoint ); @@ -8172,7 +8111,7 @@ } - }; + } ); /** * @author bhouston / http://clara.io @@ -8186,9 +8125,7 @@ } - Sphere.prototype = { - - constructor: Sphere, + Object.assign( Sphere.prototype, { set: function ( center, radius ) { @@ -8201,12 +8138,10 @@ setFromPoints: function () { - var box; + var box = new Box3(); return function setFromPoints( points, optionalCenter ) { - if ( box === undefined ) box = new Box3(); // see #10547 - var center = this.center; if ( optionalCenter !== undefined ) { @@ -8349,7 +8284,7 @@ } - }; + } ); /** * @author alteredq / http://alteredqualia.com/ @@ -8360,13 +8295,13 @@ function Matrix3() { - this.elements = new Float32Array( [ + this.elements = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 - ] ); + ]; if ( arguments.length > 0 ) { @@ -8376,9 +8311,7 @@ } - Matrix3.prototype = { - - constructor: Matrix3, + Object.assign( Matrix3.prototype, { isMatrix3: true, @@ -8416,21 +8349,18 @@ copy: function ( m ) { + var te = this.elements; var me = m.elements; - this.set( - - me[ 0 ], me[ 3 ], me[ 6 ], - me[ 1 ], me[ 4 ], me[ 7 ], - me[ 2 ], me[ 5 ], me[ 8 ] - - ); + te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; + te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; + te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ]; return this; }, - setFromMatrix4: function( m ) { + setFromMatrix4: function ( m ) { var me = m.elements; @@ -8448,12 +8378,10 @@ applyToBufferAttribute: function () { - var v1; + var v1 = new Vector3(); return function applyToBufferAttribute( attribute ) { - if ( v1 === undefined ) v1 = new Vector3(); - for ( var i = 0, l = attribute.count; i < l; i ++ ) { v1.x = attribute.getX( i ); @@ -8472,6 +8400,48 @@ }(), + multiply: function ( m ) { + + return this.multiplyMatrices( this, m ); + + }, + + premultiply: function ( m ) { + + return this.multiplyMatrices( m, this ); + + }, + + multiplyMatrices: function ( a, b ) { + + var ae = a.elements; + var be = b.elements; + var te = this.elements; + + var a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ]; + var a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ]; + var a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ]; + + var b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ]; + var b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ]; + var b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ]; + + te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31; + te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32; + te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33; + + te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31; + te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32; + te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33; + + te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31; + te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32; + te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33; + + return this; + + }, + multiplyScalar: function ( s ) { var te = this.elements; @@ -8532,6 +8502,7 @@ } return this.identity(); + } var detInv = 1 / det; @@ -8588,11 +8559,26 @@ }, + equals: function ( matrix ) { + + var te = this.elements; + var me = matrix.elements; + + for ( var i = 0; i < 9; i ++ ) { + + if ( te[ i ] !== me[ i ] ) return false; + + } + + return true; + + }, + fromArray: function ( array, offset ) { if ( offset === undefined ) offset = 0; - for( var i = 0; i < 9; i ++ ) { + for ( var i = 0; i < 9; i ++ ) { this.elements[ i ] = array[ i + offset ]; @@ -8619,13 +8605,13 @@ array[ offset + 6 ] = te[ 6 ]; array[ offset + 7 ] = te[ 7 ]; - array[ offset + 8 ] = te[ 8 ]; + array[ offset + 8 ] = te[ 8 ]; return array; } - }; + } ); /** * @author bhouston / http://clara.io @@ -8638,9 +8624,7 @@ } - Plane.prototype = { - - constructor: Plane, + Object.assign( Plane.prototype, { set: function ( normal, constant ) { @@ -8858,7 +8842,7 @@ } - }; + } ); /** * @author mrdoob / http://mrdoob.com/ @@ -8881,9 +8865,7 @@ } - Frustum.prototype = { - - constructor: Frustum, + Object.assign( Frustum.prototype, { set: function ( p0, p1, p2, p3, p4, p5 ) { @@ -9007,7 +8989,7 @@ var planes = this.planes; - for ( var i = 0; i < 6 ; i ++ ) { + for ( var i = 0; i < 6; i ++ ) { var plane = planes[ i ]; @@ -9037,7 +9019,6 @@ }(), - containsPoint: function ( point ) { var planes = this.planes; @@ -9056,7 +9037,7 @@ } - }; + } ); /** * @author alteredq / http://alteredqualia.com/ @@ -9066,29 +9047,27 @@ function WebGLShadowMap( _renderer, _lights, _objects, capabilities ) { var _gl = _renderer.context, - _state = _renderer.state, - _frustum = new Frustum(), - _projScreenMatrix = new Matrix4(), + _state = _renderer.state, + _frustum = new Frustum(), + _projScreenMatrix = new Matrix4(), - _lightShadows = _lights.shadows, + _lightShadows = _lights.shadows, - _shadowMapSize = new Vector2(), - _maxShadowMapSize = new Vector2( capabilities.maxTextureSize, capabilities.maxTextureSize ), + _shadowMapSize = new Vector2(), + _maxShadowMapSize = new Vector2( capabilities.maxTextureSize, capabilities.maxTextureSize ), - _lookTarget = new Vector3(), - _lightPositionWorld = new Vector3(), + _lookTarget = new Vector3(), + _lightPositionWorld = new Vector3(), - _renderList = [], + _MorphingFlag = 1, + _SkinningFlag = 2, - _MorphingFlag = 1, - _SkinningFlag = 2, + _NumberOfMaterialVariants = ( _MorphingFlag | _SkinningFlag ) + 1, - _NumberOfMaterialVariants = ( _MorphingFlag | _SkinningFlag ) + 1, + _depthMaterials = new Array( _NumberOfMaterialVariants ), + _distanceMaterials = new Array( _NumberOfMaterialVariants ), - _depthMaterials = new Array( _NumberOfMaterialVariants ), - _distanceMaterials = new Array( _NumberOfMaterialVariants ), - - _materialCache = {}; + _materialCache = {}; var cubeDirections = [ new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ), @@ -9163,9 +9142,9 @@ if ( _lightShadows.length === 0 ) return; // Set GL state for depth map. - _state.buffers.color.setClear( 1, 1, 1, 1 ); _state.disable( _gl.BLEND ); - _state.setDepthTest( true ); + _state.buffers.color.setClear( 1, 1, 1, 1 ); + _state.buffers.depth.setTest( true ); _state.setScissorTest( false ); // render depth map @@ -9185,6 +9164,10 @@ } var shadowCamera = shadow.camera; + var shadowMatrix = shadow.matrix; + + _lightPositionWorld.setFromMatrixPosition( light.matrixWorld ); + shadowCamera.position.copy( _lightPositionWorld ); _shadowMapSize.copy( shadow.mapSize ); _shadowMapSize.min( _maxShadowMapSize ); @@ -9226,67 +9209,19 @@ _shadowMapSize.x *= 4.0; _shadowMapSize.y *= 2.0; + + // for point lights we set the shadow matrix to be a translation-only matrix + // equal to inverse of the light's position + + shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z ); + } else { faceCount = 1; isPointLight = false; - } - - if ( shadow.map === null ) { - - var pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat }; - - shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars ); - - shadowCamera.updateProjectionMatrix(); - - } - - if ( shadow.isSpotLightShadow ) { - - shadow.update( light ); - - } - - // TODO (abelnation / sam-g-steel): is this needed? - if (shadow && shadow.isRectAreaLightShadow ) { - - shadow.update( light ); - - } - - var shadowMap = shadow.map; - var shadowMatrix = shadow.matrix; - - _lightPositionWorld.setFromMatrixPosition( light.matrixWorld ); - shadowCamera.position.copy( _lightPositionWorld ); - - _renderer.setRenderTarget( shadowMap ); - _renderer.clear(); - - // render shadow map for each cube face (if omni-directional) or - // run a single pass if not - - for ( var face = 0; face < faceCount; face ++ ) { - - if ( isPointLight ) { - - _lookTarget.copy( shadowCamera.position ); - _lookTarget.add( cubeDirections[ face ] ); - shadowCamera.up.copy( cubeUps[ face ] ); - shadowCamera.lookAt( _lookTarget ); - - var vpDimensions = cube2DViewPorts[ face ]; - _state.viewport( vpDimensions ); - - } else { - - _lookTarget.setFromMatrixPosition( light.target.matrixWorld ); - shadowCamera.lookAt( _lookTarget ); - - } - + _lookTarget.setFromMatrixPosition( light.target.matrixWorld ); + shadowCamera.lookAt( _lookTarget ); shadowCamera.updateMatrixWorld(); shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld ); @@ -9302,6 +9237,49 @@ shadowMatrix.multiply( shadowCamera.projectionMatrix ); shadowMatrix.multiply( shadowCamera.matrixWorldInverse ); + } + + if ( shadow.map === null ) { + + var pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat }; + + shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars ); + shadow.map.texture.name = light.name + ".shadowMap"; + + shadowCamera.updateProjectionMatrix(); + + } + + if ( shadow.isSpotLightShadow ) { + + shadow.update( light ); + + } + + var shadowMap = shadow.map; + + _renderer.setRenderTarget( shadowMap ); + _renderer.clear(); + + // render shadow map for each cube face (if omni-directional) or + // run a single pass if not + + for ( var face = 0; face < faceCount; face ++ ) { + + if ( isPointLight ) { + + _lookTarget.copy( shadowCamera.position ); + _lookTarget.add( cubeDirections[ face ] ); + shadowCamera.up.copy( cubeUps[ face ] ); + shadowCamera.lookAt( _lookTarget ); + shadowCamera.updateMatrixWorld(); + shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld ); + + var vpDimensions = cube2DViewPorts[ face ]; + _state.viewport( vpDimensions ); + + } + // update camera matrices and frustum _projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); @@ -9309,54 +9287,15 @@ // set object matrices & frustum culling - _renderList.length = 0; - - projectObject( scene, camera, shadowCamera ); - - // render shadow map - // render regular objects - - for ( var j = 0, jl = _renderList.length; j < jl; j ++ ) { - - var object = _renderList[ j ]; - var geometry = _objects.update( object ); - var material = object.material; - - if ( material && material.isMultiMaterial ) { - - var groups = geometry.groups; - var materials = material.materials; - - for ( var k = 0, kl = groups.length; k < kl; k ++ ) { - - var group = groups[ k ]; - var groupMaterial = materials[ group.materialIndex ]; - - if ( groupMaterial.visible === true ) { - - var depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld ); - _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group ); - - } - - } - - } else { - - var depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld ); - _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null ); - - } - - } + renderObject( scene, camera, shadowCamera, isPointLight ); } } // Restore GL state. - var clearColor = _renderer.getClearColor(), - clearAlpha = _renderer.getClearAlpha(); + var clearColor = _renderer.getClearColor(); + var clearAlpha = _renderer.getClearAlpha(); _renderer.setClearColor( clearColor, clearAlpha ); scope.needsUpdate = false; @@ -9397,6 +9336,12 @@ } + if ( object.isSkinnedMesh && material.skinning === false ) { + + console.warn( 'THREE.WebGLShadowMap: THREE.SkinnedMesh with material.skinning set to false:', object ); + + } + var useSkinning = object.isSkinnedMesh && material.skinning; var variantIndex = 0; @@ -9413,7 +9358,7 @@ } if ( _renderer.localClippingEnabled && - material.clipShadows === true && + material.clipShadows === true && material.clippingPlanes.length !== 0 ) { // in this case we need a unique material instance reflecting the @@ -9479,22 +9424,43 @@ } - function projectObject( object, camera, shadowCamera ) { + function renderObject( object, camera, shadowCamera, isPointLight ) { if ( object.visible === false ) return; - var visible = ( object.layers.mask & camera.layers.mask ) !== 0; + var visible = object.layers.test( camera.layers ); if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) { - if ( object.castShadow && ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) ) { + if ( object.castShadow && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) { + object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); + + var geometry = _objects.update( object ); var material = object.material; - if ( material.visible === true ) { + if ( Array.isArray( material ) ) { - object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); - _renderList.push( object ); + var groups = geometry.groups; + + for ( var k = 0, kl = groups.length; k < kl; k ++ ) { + + var group = groups[ k ]; + var groupMaterial = material[ group.materialIndex ]; + + if ( groupMaterial && groupMaterial.visible ) { + + var depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld ); + _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group ); + + } + + } + + } else if ( material.visible ) { + + var depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld ); + _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null ); } @@ -9506,7 +9472,7 @@ for ( var i = 0, l = children.length; i < l; i ++ ) { - projectObject( children[ i ], camera, shadowCamera ); + renderObject( children[ i ], camera, shadowCamera, isPointLight ); } @@ -9525,9 +9491,7 @@ } - Ray.prototype = { - - constructor: Ray, + Object.assign( Ray.prototype, { set: function ( origin, direction ) { @@ -9839,8 +9803,6 @@ }, - - intersectsPlane: function ( plane ) { // check if the ray lies on the plane first @@ -10048,7 +10010,7 @@ } - }; + } ); /** * @author mrdoob / http://mrdoob.com/ @@ -10069,64 +10031,82 @@ Euler.DefaultOrder = 'XYZ'; - Euler.prototype = { + Object.defineProperties( Euler.prototype, { - constructor: Euler, + x: { + + get: function () { + + return this._x; + + }, + + set: function ( value ) { + + this._x = value; + this.onChangeCallback(); + + } + + }, + + y: { + + get: function () { + + return this._y; + + }, + + set: function ( value ) { + + this._y = value; + this.onChangeCallback(); + + } + + }, + + z: { + + get: function () { + + return this._z; + + }, + + set: function ( value ) { + + this._z = value; + this.onChangeCallback(); + + } + + }, + + order: { + + get: function () { + + return this._order; + + }, + + set: function ( value ) { + + this._order = value; + this.onChangeCallback(); + + } + + } + + } ); + + Object.assign( Euler.prototype, { isEuler: true, - get x () { - - return this._x; - - }, - - set x ( value ) { - - this._x = value; - this.onChangeCallback(); - - }, - - get y () { - - return this._y; - - }, - - set y ( value ) { - - this._y = value; - this.onChangeCallback(); - - }, - - get z () { - - return this._z; - - }, - - set z ( value ) { - - this._z = value; - this.onChangeCallback(); - - }, - - get order () { - - return this._order; - - }, - - set order ( value ) { - - this._order = value; - this.onChangeCallback(); - - }, - set: function ( x, y, z, order ) { this._x = x; @@ -10284,12 +10264,10 @@ setFromQuaternion: function () { - var matrix; + var matrix = new Matrix4(); return function setFromQuaternion( q, order, update ) { - if ( matrix === undefined ) matrix = new Matrix4(); - matrix.makeRotationFromQuaternion( q ); return this.setFromRotationMatrix( matrix, order, update ); @@ -10377,7 +10355,7 @@ onChangeCallback: function () {} - }; + } ); /** * @author mrdoob / http://mrdoob.com/ @@ -10385,35 +10363,33 @@ function Layers() { - this.mask = 1; + this.mask = 1 | 0; } - Layers.prototype = { - - constructor: Layers, + Object.assign( Layers.prototype, { set: function ( channel ) { - this.mask = 1 << channel; + this.mask = 1 << channel | 0; }, enable: function ( channel ) { - this.mask |= 1 << channel; + this.mask |= 1 << channel | 0; }, toggle: function ( channel ) { - this.mask ^= 1 << channel; + this.mask ^= 1 << channel | 0; }, disable: function ( channel ) { - this.mask &= ~ ( 1 << channel ); + this.mask &= ~ ( 1 << channel | 0 ); }, @@ -10423,7 +10399,7 @@ } - }; + } ); /** * @author mrdoob / http://mrdoob.com/ @@ -10519,9 +10495,7 @@ Object3D.DefaultUp = new Vector3( 0, 1, 0 ); Object3D.DefaultMatrixAutoUpdate = true; - Object3D.prototype = { - - constructor: Object3D, + Object.assign( Object3D.prototype, EventDispatcher.prototype, { isObject3D: true, @@ -10699,7 +10673,15 @@ return function lookAt( vector ) { - m1.lookAt( vector, this.position, this.up ); + if ( this.isCamera ) { + + m1.lookAt( this.position, vector, this.up ); + + } else { + + m1.lookAt( vector, this.position, this.up ); + + } this.quaternion.setFromRotationMatrix( m1 ); @@ -10946,9 +10928,9 @@ updateMatrixWorld: function ( force ) { - if ( this.matrixAutoUpdate === true ) this.updateMatrix(); + if ( this.matrixAutoUpdate ) this.updateMatrix(); - if ( this.matrixWorldNeedsUpdate === true || force === true ) { + if ( this.matrixWorldNeedsUpdate || force ) { if ( this.parent === null ) { @@ -10999,7 +10981,7 @@ }; output.metadata = { - version: 4.4, + version: 4.5, type: 'Object', generator: 'Object3D.toJSON' }; @@ -11023,28 +11005,44 @@ // - if ( this.geometry !== undefined ) { + function serialize( library, element ) { - if ( meta.geometries[ this.geometry.uuid ] === undefined ) { + if ( library[ element.uuid ] === undefined ) { - meta.geometries[ this.geometry.uuid ] = this.geometry.toJSON( meta ); + library[ element.uuid ] = element.toJSON( meta ); } - object.geometry = this.geometry.uuid; + return element.uuid; + + } + + if ( this.geometry !== undefined ) { + + object.geometry = serialize( meta.geometries, this.geometry ); } if ( this.material !== undefined ) { - if ( meta.materials[ this.material.uuid ] === undefined ) { + if ( Array.isArray( this.material ) ) { - meta.materials[ this.material.uuid ] = this.material.toJSON( meta ); + var uuids = []; + + for ( var i = 0, l = this.material.length; i < l; i ++ ) { + + uuids.push( serialize( meta.materials, this.material[ i ] ) ); + + } + + object.material = uuids; + + } else { + + object.material = serialize( meta.materials, this.material ); } - object.material = this.material.uuid; - } // @@ -11148,9 +11146,7 @@ } - }; - - Object.assign( Object3D.prototype, EventDispatcher.prototype ); + } ); /** * @author bhouston / http://clara.io @@ -11163,9 +11159,7 @@ } - Line3.prototype = { - - constructor: Line3, + Object.assign( Line3.prototype, { set: function ( start, end ) { @@ -11277,7 +11271,7 @@ } - }; + } ); /** * @author bhouston / http://clara.io @@ -11292,92 +11286,94 @@ } - Triangle.normal = function () { + Object.assign( Triangle, { - var v0 = new Vector3(); + normal: function () { - return function normal( a, b, c, optionalTarget ) { + var v0 = new Vector3(); - var result = optionalTarget || new Vector3(); + return function normal( a, b, c, optionalTarget ) { - result.subVectors( c, b ); - v0.subVectors( a, b ); - result.cross( v0 ); + var result = optionalTarget || new Vector3(); - var resultLengthSq = result.lengthSq(); - if ( resultLengthSq > 0 ) { + result.subVectors( c, b ); + v0.subVectors( a, b ); + result.cross( v0 ); - return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) ); + var resultLengthSq = result.lengthSq(); + if ( resultLengthSq > 0 ) { - } + return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) ); - return result.set( 0, 0, 0 ); + } - }; + return result.set( 0, 0, 0 ); - }(); + }; - // static/instance method to calculate barycentric coordinates - // based on: http://www.blackpawn.com/texts/pointinpoly/default.html - Triangle.barycoordFromPoint = function () { + }(), - var v0 = new Vector3(); - var v1 = new Vector3(); - var v2 = new Vector3(); + // static/instance method to calculate barycentric coordinates + // based on: http://www.blackpawn.com/texts/pointinpoly/default.html + barycoordFromPoint: function () { - return function barycoordFromPoint( point, a, b, c, optionalTarget ) { + var v0 = new Vector3(); + var v1 = new Vector3(); + var v2 = new Vector3(); - v0.subVectors( c, a ); - v1.subVectors( b, a ); - v2.subVectors( point, a ); + return function barycoordFromPoint( point, a, b, c, optionalTarget ) { - var dot00 = v0.dot( v0 ); - var dot01 = v0.dot( v1 ); - var dot02 = v0.dot( v2 ); - var dot11 = v1.dot( v1 ); - var dot12 = v1.dot( v2 ); + v0.subVectors( c, a ); + v1.subVectors( b, a ); + v2.subVectors( point, a ); - var denom = ( dot00 * dot11 - dot01 * dot01 ); + var dot00 = v0.dot( v0 ); + var dot01 = v0.dot( v1 ); + var dot02 = v0.dot( v2 ); + var dot11 = v1.dot( v1 ); + var dot12 = v1.dot( v2 ); - var result = optionalTarget || new Vector3(); + var denom = ( dot00 * dot11 - dot01 * dot01 ); - // collinear or singular triangle - if ( denom === 0 ) { + var result = optionalTarget || new Vector3(); - // arbitrary location outside of triangle? - // not sure if this is the best idea, maybe should be returning undefined - return result.set( - 2, - 1, - 1 ); + // collinear or singular triangle + if ( denom === 0 ) { - } + // arbitrary location outside of triangle? + // not sure if this is the best idea, maybe should be returning undefined + return result.set( - 2, - 1, - 1 ); - var invDenom = 1 / denom; - var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; - var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; + } - // barycentric coordinates must always sum to 1 - return result.set( 1 - u - v, v, u ); + var invDenom = 1 / denom; + var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; + var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; - }; + // barycentric coordinates must always sum to 1 + return result.set( 1 - u - v, v, u ); - }(); + }; - Triangle.containsPoint = function () { + }(), - var v1 = new Vector3(); + containsPoint: function () { - return function containsPoint( point, a, b, c ) { + var v1 = new Vector3(); - var result = Triangle.barycoordFromPoint( point, a, b, c, v1 ); + return function containsPoint( point, a, b, c ) { - return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 ); + var result = Triangle.barycoordFromPoint( point, a, b, c, v1 ); - }; + return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 ); - }(); + }; - Triangle.prototype = { + }() - constructor: Triangle, + } ); + + Object.assign( Triangle.prototype, { set: function ( a, b, c ) { @@ -11466,19 +11462,13 @@ closestPointToPoint: function () { - var plane, edgeList, projectedPoint, closestPoint; + var plane = new Plane(); + var edgeList = [ new Line3(), new Line3(), new Line3() ]; + var projectedPoint = new Vector3(); + var closestPoint = new Vector3(); return function closestPointToPoint( point, optionalTarget ) { - if ( plane === undefined ) { - - plane = new Plane(); - edgeList = [ new Line3(), new Line3(), new Line3() ]; - projectedPoint = new Vector3(); - closestPoint = new Vector3(); - - } - var result = optionalTarget || new Vector3(); var minDistance = Infinity; @@ -11533,7 +11523,7 @@ } - }; + } ); /** * @author mrdoob / http://mrdoob.com/ @@ -11546,19 +11536,17 @@ this.b = b; this.c = c; - this.normal = (normal && normal.isVector3) ? normal : new Vector3(); + this.normal = ( normal && normal.isVector3 ) ? normal : new Vector3(); this.vertexNormals = Array.isArray( normal ) ? normal : []; - this.color = (color && color.isColor) ? color : new Color(); + this.color = ( color && color.isColor ) ? color : new Color(); this.vertexColors = Array.isArray( color ) ? color : []; this.materialIndex = materialIndex !== undefined ? materialIndex : 0; } - Face3.prototype = { - - constructor: Face3, + Object.assign( Face3.prototype, { clone: function () { @@ -11593,7 +11581,7 @@ } - }; + } ); /** * @author mrdoob / http://mrdoob.com/ @@ -11738,17 +11726,19 @@ } - BufferAttribute.prototype = { + Object.defineProperty( BufferAttribute.prototype, 'needsUpdate', { - constructor: BufferAttribute, - - isBufferAttribute: true, - - set needsUpdate( value ) { + set: function ( value ) { if ( value === true ) this.version ++; - }, + } + + } ); + + Object.assign( BufferAttribute.prototype, { + + isBufferAttribute: true, setArray: function ( array ) { @@ -12041,7 +12031,7 @@ } - }; + } ); // @@ -12393,19 +12383,15 @@ } ); - // http://stackoverflow.com/questions/1669190/javascript-min-max-array-values/13440842#13440842 - function arrayMax( array ) { - var length = array.length, max = - Infinity; + if ( array.length === 0 ) return - Infinity; - while ( length -- ) { + var max = array[ 0 ]; - if ( array[ length ] > max ) { + for ( var i = 1, l = array.length; i < l; ++ i ) { - max = array[ length ]; - - } + if ( array[ i ] > max ) max = array[ i ]; } @@ -12462,9 +12448,7 @@ } - Geometry.prototype = { - - constructor: Geometry, + Object.assign( Geometry.prototype, EventDispatcher.prototype, { isGeometry: true, @@ -12515,12 +12499,10 @@ // rotate geometry around world x-axis - var m1; + var m1 = new Matrix4(); return function rotateX( angle ) { - if ( m1 === undefined ) m1 = new Matrix4(); - m1.makeRotationX( angle ); this.applyMatrix( m1 ); @@ -12535,12 +12517,10 @@ // rotate geometry around world y-axis - var m1; + var m1 = new Matrix4(); return function rotateY( angle ) { - if ( m1 === undefined ) m1 = new Matrix4(); - m1.makeRotationY( angle ); this.applyMatrix( m1 ); @@ -12555,12 +12535,10 @@ // rotate geometry around world z-axis - var m1; + var m1 = new Matrix4(); return function rotateZ( angle ) { - if ( m1 === undefined ) m1 = new Matrix4(); - m1.makeRotationZ( angle ); this.applyMatrix( m1 ); @@ -12575,12 +12553,10 @@ // translate geometry - var m1; + var m1 = new Matrix4(); return function translate( x, y, z ) { - if ( m1 === undefined ) m1 = new Matrix4(); - m1.makeTranslation( x, y, z ); this.applyMatrix( m1 ); @@ -12595,12 +12571,10 @@ // scale geometry - var m1; + var m1 = new Matrix4(); return function scale( x, y, z ) { - if ( m1 === undefined ) m1 = new Matrix4(); - m1.makeScale( x, y, z ); this.applyMatrix( m1 ); @@ -12613,12 +12587,10 @@ lookAt: function () { - var obj; + var obj = new Object3D(); return function lookAt( vector ) { - if ( obj === undefined ) obj = new Object3D(); - obj.lookAt( vector ); obj.updateMatrix(); @@ -12701,42 +12673,50 @@ } - if ( indices !== undefined ) { + var groups = geometry.groups; - var groups = geometry.groups; + if ( groups.length > 0 ) { - if ( groups.length > 0 ) { + for ( var i = 0; i < groups.length; i ++ ) { - for ( var i = 0; i < groups.length; i ++ ) { + var group = groups[ i ]; - var group = groups[ i ]; + var start = group.start; + var count = group.count; - var start = group.start; - var count = group.count; + for ( var j = start, jl = start + count; j < jl; j += 3 ) { - for ( var j = start, jl = start + count; j < jl; j += 3 ) { + if ( indices !== undefined ) { addFace( indices[ j ], indices[ j + 1 ], indices[ j + 2 ], group.materialIndex ); + } else { + + addFace( j, j + 1, j + 2, group.materialIndex ); + } } - } else { - - for ( var i = 0; i < indices.length; i += 3 ) { - - addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); - - } - } } else { - for ( var i = 0; i < positions.length / 3; i += 3 ) { + if ( indices !== undefined ) { - addFace( i, i + 1, i + 2 ); + for ( var i = 0; i < indices.length; i += 3 ) { + + addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); + + } + + } else { + + for ( var i = 0; i < positions.length / 3; i += 3 ) { + + addFace( i, i + 1, i + 2 ); + + } } @@ -13117,15 +13097,15 @@ } var normalMatrix, - vertexOffset = this.vertices.length, - vertices1 = this.vertices, - vertices2 = geometry.vertices, - faces1 = this.faces, - faces2 = geometry.faces, - uvs1 = this.faceVertexUvs[ 0 ], - uvs2 = geometry.faceVertexUvs[ 0 ], - colors1 = this.colors, - colors2 = geometry.colors; + vertexOffset = this.vertices.length, + vertices1 = this.vertices, + vertices2 = geometry.vertices, + faces1 = this.faces, + faces2 = geometry.faces, + uvs1 = this.faceVertexUvs[ 0 ], + uvs2 = geometry.faceVertexUvs[ 0 ], + colors1 = this.colors, + colors2 = geometry.colors; if ( materialIndexOffset === undefined ) materialIndexOffset = 0; @@ -13162,8 +13142,8 @@ for ( i = 0, il = faces2.length; i < il; i ++ ) { var face = faces2[ i ], faceCopy, normal, color, - faceVertexNormals = face.vertexNormals, - faceVertexColors = face.vertexColors; + faceVertexNormals = face.vertexNormals, + faceVertexColors = face.vertexColors; faceCopy = new Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset ); faceCopy.normal.copy( face.normal ); @@ -13382,7 +13362,7 @@ var data = { metadata: { - version: 4.4, + version: 4.5, type: 'Geometry', generator: 'Geometry.toJSON' } @@ -13574,28 +13554,28 @@ clone: function () { /* - // Handle primitives + // Handle primitives - var parameters = this.parameters; + var parameters = this.parameters; - if ( parameters !== undefined ) { + if ( parameters !== undefined ) { - var values = []; + var values = []; - for ( var key in parameters ) { + for ( var key in parameters ) { - values.push( parameters[ key ] ); + values.push( parameters[ key ] ); - } + } - var geometry = Object.create( this.constructor.prototype ); - this.constructor.apply( geometry, values ); - return geometry; + var geometry = Object.create( this.constructor.prototype ); + this.constructor.apply( geometry, values ); + return geometry; - } + } - return new this.constructor().copy( this ); - */ + return new this.constructor().copy( this ); + */ return new Geometry().copy( this ); @@ -13841,9 +13821,7 @@ } - }; - - Object.assign( Geometry.prototype, EventDispatcher.prototype ); + } ); /** * @author alteredq / http://alteredqualia.com/ @@ -13873,9 +13851,9 @@ } - BufferGeometry.prototype = { + BufferGeometry.MaxIndex = 65535; - constructor: BufferGeometry, + Object.assign( BufferGeometry.prototype, EventDispatcher.prototype, { isBufferGeometry: true, @@ -14007,12 +13985,10 @@ // rotate geometry around world x-axis - var m1; + var m1 = new Matrix4(); return function rotateX( angle ) { - if ( m1 === undefined ) m1 = new Matrix4(); - m1.makeRotationX( angle ); this.applyMatrix( m1 ); @@ -14027,12 +14003,10 @@ // rotate geometry around world y-axis - var m1; + var m1 = new Matrix4(); return function rotateY( angle ) { - if ( m1 === undefined ) m1 = new Matrix4(); - m1.makeRotationY( angle ); this.applyMatrix( m1 ); @@ -14047,12 +14021,10 @@ // rotate geometry around world z-axis - var m1; + var m1 = new Matrix4(); return function rotateZ( angle ) { - if ( m1 === undefined ) m1 = new Matrix4(); - m1.makeRotationZ( angle ); this.applyMatrix( m1 ); @@ -14067,12 +14039,10 @@ // translate geometry - var m1; + var m1 = new Matrix4(); return function translate( x, y, z ) { - if ( m1 === undefined ) m1 = new Matrix4(); - m1.makeTranslation( x, y, z ); this.applyMatrix( m1 ); @@ -14087,12 +14057,10 @@ // scale geometry - var m1; + var m1 = new Matrix4(); return function scale( x, y, z ) { - if ( m1 === undefined ) m1 = new Matrix4(); - m1.makeScale( x, y, z ); this.applyMatrix( m1 ); @@ -14105,12 +14073,10 @@ lookAt: function () { - var obj; + var obj = new Object3D(); return function lookAt( vector ) { - if ( obj === undefined ) obj = new Object3D(); - obj.lookAt( vector ); obj.updateMatrix(); @@ -14660,21 +14626,19 @@ normalizeNormals: function () { - var normals = this.attributes.normal.array; + var normals = this.attributes.normal; var x, y, z, n; - for ( var i = 0, il = normals.length; i < il; i += 3 ) { + for ( var i = 0, il = normals.count; i < il; i ++ ) { - x = normals[ i ]; - y = normals[ i + 1 ]; - z = normals[ i + 2 ]; + x = normals.getX( i ); + y = normals.getY( i ); + z = normals.getZ( i ); n = 1.0 / Math.sqrt( x * x + y * y + z * z ); - normals[ i ] *= n; - normals[ i + 1 ] *= n; - normals[ i + 2 ] *= n; + normals.setXYZ( i, x * n, y * n, z * n ); } @@ -14729,7 +14693,7 @@ var data = { metadata: { - version: 4.4, + version: 4.5, type: 'BufferGeometry', generator: 'BufferGeometry.toJSON' } @@ -14813,28 +14777,28 @@ clone: function () { /* - // Handle primitives + // Handle primitives - var parameters = this.parameters; + var parameters = this.parameters; - if ( parameters !== undefined ) { + if ( parameters !== undefined ) { - var values = []; + var values = []; - for ( var key in parameters ) { + for ( var key in parameters ) { - values.push( parameters[ key ] ); + values.push( parameters[ key ] ); - } + } - var geometry = Object.create( this.constructor.prototype ); - this.constructor.apply( geometry, values ); - return geometry; + var geometry = Object.create( this.constructor.prototype ); + this.constructor.apply( geometry, values ); + return geometry; - } + } - return new this.constructor().copy( this ); - */ + return new this.constructor().copy( this ); + */ return new BufferGeometry().copy( this ); @@ -14943,11 +14907,7 @@ } - }; - - BufferGeometry.MaxIndex = 65535; - - Object.assign( BufferGeometry.prototype, EventDispatcher.prototype ); + } ); /** * @author mrdoob / http://mrdoob.com/ @@ -15098,7 +15058,7 @@ uvB.fromBufferAttribute( uv, b ); uvC.fromBufferAttribute( uv, c ); - intersection.uv = uvIntersection( intersectionPoint, vA, vB, vC, uvA, uvB, uvC ); + intersection.uv = uvIntersection( intersectionPoint, vA, vB, vC, uvA, uvB, uvC ); } @@ -15198,8 +15158,7 @@ } else if ( geometry.isGeometry ) { var fvA, fvB, fvC; - var isFaceMaterial = ( material && material.isMultiMaterial ); - var materials = isFaceMaterial === true ? material.materials : null; + var isMultiMaterial = Array.isArray( material ); var vertices = geometry.vertices; var faces = geometry.faces; @@ -15211,7 +15170,7 @@ for ( var f = 0, fl = faces.length; f < fl; f ++ ) { var face = faces[ f ]; - var faceMaterial = isFaceMaterial === true ? materials[ face.materialIndex ] : material; + var faceMaterial = isMultiMaterial ? material[ face.materialIndex ] : material; if ( faceMaterial === undefined ) continue; @@ -15256,7 +15215,7 @@ if ( intersection ) { - if ( uvs ) { + if ( uvs && uvs[ f ] ) { var uvs_f = uvs[ f ]; uvA.copy( uvs_f[ 0 ] ); @@ -15291,9 +15250,11 @@ /** * @author mrdoob / http://mrdoob.com/ - * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as + * @author Mugen87 / https://github.com/Mugen87 */ + // BoxGeometry + function BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) { Geometry.call( this ); @@ -15317,9 +15278,7 @@ BoxGeometry.prototype = Object.create( Geometry.prototype ); BoxGeometry.prototype.constructor = BoxGeometry; - /** - * @author Mugen87 / https://github.com/Mugen87 - */ + // BoxBufferGeometry function BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) { @@ -15483,9 +15442,11 @@ /** * @author mrdoob / http://mrdoob.com/ - * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as + * @author Mugen87 / https://github.com/Mugen87 */ + // PlaneGeometry + function PlaneGeometry( width, height, widthSegments, heightSegments ) { Geometry.call( this ); @@ -15500,18 +15461,14 @@ }; this.fromBufferGeometry( new PlaneBufferGeometry( width, height, widthSegments, heightSegments ) ); + this.mergeVertices(); } PlaneGeometry.prototype = Object.create( Geometry.prototype ); PlaneGeometry.prototype.constructor = PlaneGeometry; - /** - * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / https://github.com/Mugen87 - * - * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as - */ + // PlaneBufferGeometry function PlaneBufferGeometry( width, height, widthSegments, heightSegments ) { @@ -15617,59 +15574,46 @@ } - Camera.prototype = Object.create( Object3D.prototype ); - Camera.prototype.constructor = Camera; + Camera.prototype = Object.assign( Object.create( Object3D.prototype ), { - Camera.prototype.isCamera = true; + constructor: Camera, - Camera.prototype.getWorldDirection = function () { + isCamera: true, - var quaternion = new Quaternion(); + copy: function ( source ) { - return function getWorldDirection( optionalTarget ) { + Object3D.prototype.copy.call( this, source ); - var result = optionalTarget || new Vector3(); + this.matrixWorldInverse.copy( source.matrixWorldInverse ); + this.projectionMatrix.copy( source.projectionMatrix ); - this.getWorldQuaternion( quaternion ); + return this; - return result.set( 0, 0, - 1 ).applyQuaternion( quaternion ); + }, - }; + getWorldDirection: function () { - }(); + var quaternion = new Quaternion(); - Camera.prototype.lookAt = function () { + return function getWorldDirection( optionalTarget ) { - // This routine does not support cameras with rotated and/or translated parent(s) + var result = optionalTarget || new Vector3(); - var m1 = new Matrix4(); + this.getWorldQuaternion( quaternion ); - return function lookAt( vector ) { + return result.set( 0, 0, - 1 ).applyQuaternion( quaternion ); - m1.lookAt( this.position, vector, this.up ); + }; - this.quaternion.setFromRotationMatrix( m1 ); + }(), - }; + clone: function () { - }(); + return new this.constructor().copy( this ); - Camera.prototype.clone = function () { + } - return new this.constructor().copy( this ); - - }; - - Camera.prototype.copy = function ( source ) { - - Object3D.prototype.copy.call( this, source ); - - this.matrixWorldInverse.copy( source.matrixWorldInverse ); - this.projectionMatrix.copy( source.projectionMatrix ); - - return this; - - }; + } ); /** * @author mrdoob / http://mrdoob.com/ @@ -15830,7 +15774,7 @@ }, - clearViewOffset: function() { + clearViewOffset: function () { this.view = null; this.updateProjectionMatrix(); @@ -16012,6 +15956,335 @@ } ); + /** + * @author mrdoob / http://mrdoob.com/ + */ + + function WebGLAttributes( gl ) { + + var buffers = {}; + + function createBuffer( attribute, bufferType ) { + + var array = attribute.array; + var usage = attribute.dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW; + + var buffer = gl.createBuffer(); + + gl.bindBuffer( bufferType, buffer ); + gl.bufferData( bufferType, array, usage ); + + attribute.onUploadCallback(); + + var type = gl.FLOAT; + + if ( array instanceof Float32Array ) { + + type = gl.FLOAT; + + } else if ( array instanceof Float64Array ) { + + console.warn( "Unsupported data buffer format: Float64Array" ); + + } else if ( array instanceof Uint16Array ) { + + type = gl.UNSIGNED_SHORT; + + } else if ( array instanceof Int16Array ) { + + type = gl.SHORT; + + } else if ( array instanceof Uint32Array ) { + + type = gl.UNSIGNED_INT; + + } else if ( array instanceof Int32Array ) { + + type = gl.INT; + + } else if ( array instanceof Int8Array ) { + + type = gl.BYTE; + + } else if ( array instanceof Uint8Array ) { + + type = gl.UNSIGNED_BYTE; + + } + + return { + buffer: buffer, + type: type, + bytesPerElement: array.BYTES_PER_ELEMENT, + version: attribute.version + }; + + } + + function updateBuffer( buffer, attribute, bufferType ) { + + var array = attribute.array; + var updateRange = attribute.updateRange; + + gl.bindBuffer( bufferType, buffer ); + + if ( attribute.dynamic === false ) { + + gl.bufferData( bufferType, array, gl.STATIC_DRAW ); + + } else if ( updateRange.count === - 1 ) { + + // Not using update ranges + + gl.bufferSubData( bufferType, 0, array ); + + } else if ( updateRange.count === 0 ) { + + console.error( 'THREE.WebGLObjects.updateBuffer: dynamic THREE.BufferAttribute marked as needsUpdate but updateRange.count is 0, ensure you are using set methods or updating manually.' ); + + } else { + + gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, + array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) ); + + updateRange.count = 0; // reset range + + } + + } + + // + + function get( attribute ) { + + if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; + + return buffers[ attribute.uuid ]; + + } + + function remove( attribute ) { + + var data = buffers[ attribute.uuid ]; + + if ( data ) { + + gl.deleteBuffer( data.buffer ); + + delete buffers[ attribute.uuid ]; + + } + + } + + function update( attribute, bufferType ) { + + if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; + + var data = buffers[ attribute.uuid ]; + + if ( data === undefined ) { + + buffers[ attribute.uuid ] = createBuffer( attribute, bufferType ); + + } else if ( data.version < attribute.version ) { + + updateBuffer( data.buffer, attribute, bufferType ); + + data.version = attribute.version; + + } + + } + + return { + + get: get, + remove: remove, + update: update + + }; + + } + + /** + * @author mrdoob / http://mrdoob.com/ + */ + + function painterSortStable( a, b ) { + + if ( a.renderOrder !== b.renderOrder ) { + + return a.renderOrder - b.renderOrder; + + } else if ( a.program && b.program && a.program !== b.program ) { + + return a.program.id - b.program.id; + + } else if ( a.material.id !== b.material.id ) { + + return a.material.id - b.material.id; + + } else if ( a.z !== b.z ) { + + return a.z - b.z; + + } else { + + return a.id - b.id; + + } + + } + + function reversePainterSortStable( a, b ) { + + if ( a.renderOrder !== b.renderOrder ) { + + return a.renderOrder - b.renderOrder; + + } if ( a.z !== b.z ) { + + return b.z - a.z; + + } else { + + return a.id - b.id; + + } + + } + + function WebGLRenderList() { + + var opaque = []; + var opaqueLastIndex = - 1; + + var transparent = []; + var transparentLastIndex = - 1; + + function init() { + + opaqueLastIndex = - 1; + transparentLastIndex = - 1; + + } + + function push( object, geometry, material, z, group ) { + + var array, index; + + // allocate the next position in the appropriate array + + if ( material.transparent ) { + + array = transparent; + index = ++ transparentLastIndex; + + } else { + + array = opaque; + index = ++ opaqueLastIndex; + + } + + // recycle existing render item or grow the array + + var renderItem = array[ index ]; + + if ( renderItem ) { + + renderItem.id = object.id; + renderItem.object = object; + renderItem.geometry = geometry; + renderItem.material = material; + renderItem.program = material.program; + renderItem.renderOrder = object.renderOrder; + renderItem.z = z; + renderItem.group = group; + + } else { + + renderItem = { + id: object.id, + object: object, + geometry: geometry, + material: material, + program: material.program, + renderOrder: object.renderOrder, + z: z, + group: group + }; + + // assert( index === array.length ); + array.push( renderItem ); + + } + + } + + function finish() { + + opaque.length = opaqueLastIndex + 1; + transparent.length = transparentLastIndex + 1; + + } + + function sort() { + + opaque.sort( painterSortStable ); + transparent.sort( reversePainterSortStable ); + + } + + return { + opaque: opaque, + transparent: transparent, + + init: init, + push: push, + finish: finish, + + sort: sort + }; + + } + + function WebGLRenderLists() { + + var lists = {}; + + function get( scene, camera ) { + + var hash = scene.id + ',' + camera.id; + var list = lists[ hash ]; + + if ( list === undefined ) { + + // console.log( 'THREE.WebGLRenderLists:', hash ); + + list = new WebGLRenderList(); + lists[ hash ] = list; + + } + + return list; + + } + + function dispose() { + + lists = {}; + + } + + return { + get: get, + dispose: dispose + }; + + } + /** * @author mrdoob / http://mrdoob.com/ */ @@ -16066,7 +16339,7 @@ if ( extension === null ) { - console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); + console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); return; } @@ -16080,14 +16353,12 @@ } - return { + // - setMode: setMode, - setIndex: setIndex, - render: render, - renderInstances: renderInstances - - }; + this.setMode = setMode; + this.setIndex = setIndex; + this.render = render; + this.renderInstances = renderInstances; } @@ -16116,7 +16387,7 @@ } - function renderInstances( geometry ) { + function renderInstances( geometry, start, count ) { var extension = extensions.get( 'ANGLE_instanced_arrays' ); @@ -16129,8 +16400,6 @@ var position = geometry.attributes.position; - var count = 0; - if ( position.isInterleavedBufferAttribute ) { count = position.data.count; @@ -16139,9 +16408,7 @@ } else { - count = position.count; - - extension.drawArraysInstancedANGLE( mode, 0, count, geometry.maxInstancedCount ); + extension.drawArraysInstancedANGLE( mode, start, count, geometry.maxInstancedCount ); } @@ -16152,10 +16419,199 @@ } + // + + this.setMode = setMode; + this.render = render; + this.renderInstances = renderInstances; + + } + + /** + * @author mrdoob / http://mrdoob.com/ + */ + + function WebGLGeometries( gl, attributes, infoMemory ) { + + var geometries = {}; + var wireframeAttributes = {}; + + function onGeometryDispose( event ) { + + var geometry = event.target; + var buffergeometry = geometries[ geometry.id ]; + + if ( buffergeometry.index !== null ) { + + attributes.remove( buffergeometry.index ); + + } + + for ( var name in buffergeometry.attributes ) { + + attributes.remove( buffergeometry.attributes[ name ] ); + + } + + geometry.removeEventListener( 'dispose', onGeometryDispose ); + + delete geometries[ geometry.id ]; + + // TODO Remove duplicate code + + var attribute = wireframeAttributes[ geometry.id ]; + + if ( attribute ) { + + attributes.remove( attribute ); + delete wireframeAttributes[ geometry.id ]; + + } + + attribute = wireframeAttributes[ buffergeometry.id ]; + + if ( attribute ) { + + attributes.remove( attribute ); + delete wireframeAttributes[ buffergeometry.id ]; + + } + + // + + infoMemory.geometries --; + + } + + function get( object, geometry ) { + + var buffergeometry = geometries[ geometry.id ]; + + if ( buffergeometry ) return buffergeometry; + + geometry.addEventListener( 'dispose', onGeometryDispose ); + + if ( geometry.isBufferGeometry ) { + + buffergeometry = geometry; + + } else if ( geometry.isGeometry ) { + + if ( geometry._bufferGeometry === undefined ) { + + geometry._bufferGeometry = new BufferGeometry().setFromObject( object ); + + } + + buffergeometry = geometry._bufferGeometry; + + } + + geometries[ geometry.id ] = buffergeometry; + + infoMemory.geometries ++; + + return buffergeometry; + + } + + function update( geometry ) { + + var index = geometry.index; + var geometryAttributes = geometry.attributes; + + if ( index !== null ) { + + attributes.update( index, gl.ELEMENT_ARRAY_BUFFER ); + + } + + for ( var name in geometryAttributes ) { + + attributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER ); + + } + + // morph targets + + var morphAttributes = geometry.morphAttributes; + + for ( var name in morphAttributes ) { + + var array = morphAttributes[ name ]; + + for ( var i = 0, l = array.length; i < l; i ++ ) { + + attributes.update( array[ i ], gl.ARRAY_BUFFER ); + + } + + } + + } + + function getWireframeAttribute( geometry ) { + + var attribute = wireframeAttributes[ geometry.id ]; + + if ( attribute ) return attribute; + + var indices = []; + + var geometryIndex = geometry.index; + var geometryAttributes = geometry.attributes; + + // console.time( 'wireframe' ); + + if ( geometryIndex !== null ) { + + var array = geometryIndex.array; + + for ( var i = 0, l = array.length; i < l; i += 3 ) { + + var a = array[ i + 0 ]; + var b = array[ i + 1 ]; + var c = array[ i + 2 ]; + + indices.push( a, b, b, c, c, a ); + + } + + } else { + + var array = geometryAttributes.position.array; + + for ( var i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) { + + var a = i + 0; + var b = i + 1; + var c = i + 2; + + indices.push( a, b, b, c, c, a ); + + } + + } + + // console.timeEnd( 'wireframe' ); + + attribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 ); + + attributes.update( attribute, gl.ELEMENT_ARRAY_BUFFER ); + + wireframeAttributes[ geometry.id ] = attribute; + + return attribute; + + } + return { - setMode: setMode, - render: render, - renderInstances: renderInstances + + get: get, + update: update, + + getWireframeAttribute: getWireframeAttribute + }; } @@ -16255,6 +16711,56 @@ } + /** + * @author mrdoob / http://mrdoob.com/ + */ + + function WebGLObjects( gl, geometries, infoRender ) { + + var updateList = {}; + + function update( object ) { + + var frame = infoRender.frame; + + var geometry = object.geometry; + var buffergeometry = geometries.get( object, geometry ); + + // Update once per frame + + if ( updateList[ buffergeometry.id ] !== frame ) { + + if ( geometry.isGeometry ) { + + buffergeometry.updateFromObject( object ); + + } + + geometries.update( buffergeometry ); + + updateList[ buffergeometry.id ] = frame; + + } + + return buffergeometry; + + } + + function clear() { + + updateList = {}; + + } + + return { + + update: update, + clear: clear + + }; + + } + /** * @author mrdoob / http://mrdoob.com/ */ @@ -16448,7 +16954,7 @@ function parseIncludes( string ) { - var pattern = /#include +<([\w\d.]+)>/g; + var pattern = /^[ \t]*#include +<([\w\d.]+)>/gm; function replace( match, include ) { @@ -16607,7 +17113,6 @@ prefixVertex = [ - 'precision ' + parameters.precision + ' float;', 'precision ' + parameters.precision + ' int;', @@ -16623,7 +17128,6 @@ ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', ( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '', - parameters.map ? '#define USE_MAP' : '', parameters.envMap ? '#define USE_ENVMAP' : '', parameters.envMap ? '#define ' + envMapModeDefine : '', @@ -16775,6 +17279,8 @@ ( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below ( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( "toneMapping", parameters.toneMapping ) : '', + parameters.dithering ? '#define DITHERING' : '', + ( parameters.outputEncoding || parameters.mapEncoding || parameters.envMapEncoding || parameters.emissiveMapEncoding ) ? ShaderChunk[ 'encodings_pars_fragment' ] : '', // this code is required here because it is used by the various encoding/decoding function defined below parameters.mapEncoding ? getTexelDecodingFunction( 'mapTexelToLinear', parameters.mapEncoding ) : '', parameters.envMapEncoding ? getTexelDecodingFunction( 'envMapTexelToLinear', parameters.envMapEncoding ) : '', @@ -16999,13 +17505,16 @@ "maxMorphTargets", "maxMorphNormals", "premultipliedAlpha", "numDirLights", "numPointLights", "numSpotLights", "numHemiLights", "numRectAreaLights", "shadowMapEnabled", "shadowMapType", "toneMapping", 'physicallyCorrectLights', - "alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking" + "alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking", "dithering" ]; function allocateBones( object ) { - if ( capabilities.floatVertexTextures && object && object.skeleton && object.skeleton.useVertexTexture ) { + var skeleton = object.skeleton; + var bones = skeleton.bones; + + if ( capabilities.floatVertexTextures ) { return 1024; @@ -17021,17 +17530,12 @@ var nVertexUniforms = capabilities.maxVertexUniforms; var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 ); - var maxBones = nVertexMatrices; + var maxBones = Math.min( nVertexMatrices, bones.length ); - if ( object !== undefined && (object && object.isSkinnedMesh) ) { + if ( maxBones < bones.length ) { - maxBones = Math.min( object.skeleton.bones.length, maxBones ); - - if ( maxBones < object.skeleton.bones.length ) { - - console.warn( 'WebGLRenderer: too many bones - ' + object.skeleton.bones.length + ', this GPU supports just ' + maxBones + ' (try OpenGL instead of ANGLE)' ); - - } + console.warn( 'THREE.WebGLRenderer: Skeleton has ' + bones.length + ' bones. This GPU supports ' + maxBones + '.' ); + return 0; } @@ -17078,7 +17582,7 @@ // heuristics to create shader parameters according to lights in the scene // (not to blow over maxLights budget) - var maxBones = allocateBones( object ); + var maxBones = object.isSkinnedMesh ? allocateBones( object ) : 0; var precision = renderer.getPrecision(); if ( material.precision !== null ) { @@ -17093,7 +17597,7 @@ } - var currentRenderTarget = renderer.getCurrentRenderTarget(); + var currentRenderTarget = renderer.getRenderTarget(); var parameters = { @@ -17128,16 +17632,16 @@ fog: !! fog, useFog: material.fog, - fogExp: (fog && fog.isFogExp2), + fogExp: ( fog && fog.isFogExp2 ), flatShading: material.shading === FlatShading, sizeAttenuation: material.sizeAttenuation, logarithmicDepthBuffer: capabilities.logarithmicDepthBuffer, - skinning: material.skinning, + skinning: material.skinning && maxBones > 0, maxBones: maxBones, - useVertexTexture: capabilities.floatVertexTextures && object && object.skeleton && object.skeleton.useVertexTexture, + useVertexTexture: capabilities.floatVertexTextures, morphTargets: material.morphTargets, morphNormals: material.morphNormals, @@ -17153,6 +17657,8 @@ numClippingPlanes: nClipPlanes, numClipIntersection: nClipIntersection, + dithering: material.dithering, + shadowMapEnabled: renderer.shadowMap.enabled && object.receiveShadow && lights.shadows.length > 0, shadowMapType: renderer.shadowMap.type, @@ -17240,7 +17746,7 @@ }; - this.releaseProgram = function( program ) { + this.releaseProgram = function ( program ) { if ( -- program.usedTimes === 0 ) { @@ -17265,410 +17771,8 @@ * @author mrdoob / http://mrdoob.com/ */ - function WebGLGeometries( gl, properties, info ) { + function WebGLTextures( _gl, extensions, state, properties, capabilities, paramThreeToGL, infoMemory ) { - var geometries = {}; - - function onGeometryDispose( event ) { - - var geometry = event.target; - var buffergeometry = geometries[ geometry.id ]; - - if ( buffergeometry.index !== null ) { - - deleteAttribute( buffergeometry.index ); - - } - - deleteAttributes( buffergeometry.attributes ); - - geometry.removeEventListener( 'dispose', onGeometryDispose ); - - delete geometries[ geometry.id ]; - - // TODO - - var property = properties.get( geometry ); - - if ( property.wireframe ) { - - deleteAttribute( property.wireframe ); - - } - - properties.delete( geometry ); - - var bufferproperty = properties.get( buffergeometry ); - - if ( bufferproperty.wireframe ) { - - deleteAttribute( bufferproperty.wireframe ); - - } - - properties.delete( buffergeometry ); - - // - - info.memory.geometries --; - - } - - function getAttributeBuffer( attribute ) { - - if ( attribute.isInterleavedBufferAttribute ) { - - return properties.get( attribute.data ).__webglBuffer; - - } - - return properties.get( attribute ).__webglBuffer; - - } - - function deleteAttribute( attribute ) { - - var buffer = getAttributeBuffer( attribute ); - - if ( buffer !== undefined ) { - - gl.deleteBuffer( buffer ); - removeAttributeBuffer( attribute ); - - } - - } - - function deleteAttributes( attributes ) { - - for ( var name in attributes ) { - - deleteAttribute( attributes[ name ] ); - - } - - } - - function removeAttributeBuffer( attribute ) { - - if ( attribute.isInterleavedBufferAttribute ) { - - properties.delete( attribute.data ); - - } else { - - properties.delete( attribute ); - - } - - } - - return { - - get: function ( object ) { - - var geometry = object.geometry; - - if ( geometries[ geometry.id ] !== undefined ) { - - return geometries[ geometry.id ]; - - } - - geometry.addEventListener( 'dispose', onGeometryDispose ); - - var buffergeometry; - - if ( geometry.isBufferGeometry ) { - - buffergeometry = geometry; - - } else if ( geometry.isGeometry ) { - - if ( geometry._bufferGeometry === undefined ) { - - geometry._bufferGeometry = new BufferGeometry().setFromObject( object ); - - } - - buffergeometry = geometry._bufferGeometry; - - } - - geometries[ geometry.id ] = buffergeometry; - - info.memory.geometries ++; - - return buffergeometry; - - } - - }; - - } - - /** - * @author mrdoob / http://mrdoob.com/ - */ - - function WebGLObjects( gl, properties, info ) { - - var geometries = new WebGLGeometries( gl, properties, info ); - - // - - function update( object ) { - - // TODO: Avoid updating twice (when using shadowMap). Maybe add frame counter. - - var geometry = geometries.get( object ); - - if ( object.geometry.isGeometry ) { - - geometry.updateFromObject( object ); - - } - - var index = geometry.index; - var attributes = geometry.attributes; - - if ( index !== null ) { - - updateAttribute( index, gl.ELEMENT_ARRAY_BUFFER ); - - } - - for ( var name in attributes ) { - - updateAttribute( attributes[ name ], gl.ARRAY_BUFFER ); - - } - - // morph targets - - var morphAttributes = geometry.morphAttributes; - - for ( var name in morphAttributes ) { - - var array = morphAttributes[ name ]; - - for ( var i = 0, l = array.length; i < l; i ++ ) { - - updateAttribute( array[ i ], gl.ARRAY_BUFFER ); - - } - - } - - return geometry; - - } - - function updateAttribute( attribute, bufferType ) { - - var data = ( attribute.isInterleavedBufferAttribute ) ? attribute.data : attribute; - - var attributeProperties = properties.get( data ); - - if ( attributeProperties.__webglBuffer === undefined ) { - - createBuffer( attributeProperties, data, bufferType ); - - } else if ( attributeProperties.version !== data.version ) { - - updateBuffer( attributeProperties, data, bufferType ); - - } - - } - - function createBuffer( attributeProperties, data, bufferType ) { - - attributeProperties.__webglBuffer = gl.createBuffer(); - gl.bindBuffer( bufferType, attributeProperties.__webglBuffer ); - - var usage = data.dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW; - - gl.bufferData( bufferType, data.array, usage ); - - var type = gl.FLOAT; - var array = data.array; - - if ( array instanceof Float32Array ) { - - type = gl.FLOAT; - - } else if ( array instanceof Float64Array ) { - - console.warn( "Unsupported data buffer format: Float64Array" ); - - } else if ( array instanceof Uint16Array ) { - - type = gl.UNSIGNED_SHORT; - - } else if ( array instanceof Int16Array ) { - - type = gl.SHORT; - - } else if ( array instanceof Uint32Array ) { - - type = gl.UNSIGNED_INT; - - } else if ( array instanceof Int32Array ) { - - type = gl.INT; - - } else if ( array instanceof Int8Array ) { - - type = gl.BYTE; - - } else if ( array instanceof Uint8Array ) { - - type = gl.UNSIGNED_BYTE; - - } - - attributeProperties.bytesPerElement = array.BYTES_PER_ELEMENT; - attributeProperties.type = type; - attributeProperties.version = data.version; - - data.onUploadCallback(); - - } - - function updateBuffer( attributeProperties, data, bufferType ) { - - gl.bindBuffer( bufferType, attributeProperties.__webglBuffer ); - - if ( data.dynamic === false ) { - - gl.bufferData( bufferType, data.array, gl.STATIC_DRAW ); - - } else if ( data.updateRange.count === - 1 ) { - - // Not using update ranges - - gl.bufferSubData( bufferType, 0, data.array ); - - } else if ( data.updateRange.count === 0 ) { - - console.error( 'THREE.WebGLObjects.updateBuffer: dynamic THREE.BufferAttribute marked as needsUpdate but updateRange.count is 0, ensure you are using set methods or updating manually.' ); - - } else { - - gl.bufferSubData( bufferType, data.updateRange.offset * data.array.BYTES_PER_ELEMENT, - data.array.subarray( data.updateRange.offset, data.updateRange.offset + data.updateRange.count ) ); - - data.updateRange.count = 0; // reset range - - } - - attributeProperties.version = data.version; - - } - - function getAttributeBuffer( attribute ) { - - if ( attribute.isInterleavedBufferAttribute ) { - - return properties.get( attribute.data ).__webglBuffer; - - } - - return properties.get( attribute ).__webglBuffer; - - } - - function getAttributeProperties( attribute ) { - - if ( attribute.isInterleavedBufferAttribute ) { - - return properties.get( attribute.data ); - - } - - return properties.get( attribute ); - - } - - function getWireframeAttribute( geometry ) { - - var property = properties.get( geometry ); - - if ( property.wireframe !== undefined ) { - - return property.wireframe; - - } - - var indices = []; - - var index = geometry.index; - var attributes = geometry.attributes; - - // console.time( 'wireframe' ); - - if ( index !== null ) { - - var array = index.array; - - for ( var i = 0, l = array.length; i < l; i += 3 ) { - - var a = array[ i + 0 ]; - var b = array[ i + 1 ]; - var c = array[ i + 2 ]; - - indices.push( a, b, b, c, c, a ); - - } - - } else { - - var array = attributes.position.array; - - for ( var i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) { - - var a = i + 0; - var b = i + 1; - var c = i + 2; - - indices.push( a, b, b, c, c, a ); - - } - - } - - // console.timeEnd( 'wireframe' ); - - var attribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 ); - - updateAttribute( attribute, gl.ELEMENT_ARRAY_BUFFER ); - - property.wireframe = attribute; - - return attribute; - - } - - return { - - getAttributeBuffer: getAttributeBuffer, - getAttributeProperties: getAttributeProperties, - getWireframeAttribute: getWireframeAttribute, - - update: update - - }; - - } - - /** - * @author mrdoob / http://mrdoob.com/ - */ - - function WebGLTextures( _gl, extensions, state, properties, capabilities, paramThreeToGL, info ) { - - var _infoMemory = info.memory; var _isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && _gl instanceof WebGL2RenderingContext ); // @@ -17757,7 +17861,7 @@ deallocateTexture( texture ); - _infoMemory.textures --; + infoMemory.textures --; } @@ -17770,7 +17874,7 @@ deallocateRenderTarget( renderTarget ); - _infoMemory.textures --; + infoMemory.textures --; } @@ -17797,7 +17901,7 @@ } // remove all webgl properties - properties.delete( texture ); + properties.remove( texture ); } @@ -17836,8 +17940,8 @@ } - properties.delete( renderTarget.texture ); - properties.delete( renderTarget ); + properties.remove( renderTarget.texture ); + properties.remove( renderTarget ); } @@ -17889,7 +17993,7 @@ textureProperties.__image__webglTextureCube = _gl.createTexture(); - _infoMemory.textures ++; + infoMemory.textures ++; } @@ -18060,7 +18164,7 @@ textureProperties.__webglTexture = _gl.createTexture(); - _infoMemory.textures ++; + infoMemory.textures ++; } @@ -18361,7 +18465,7 @@ textureProperties.__webglTexture = _gl.createTexture(); - _infoMemory.textures ++; + infoMemory.textures ++; var isCube = ( renderTarget.isWebGLRenderTargetCube === true ); var isTargetPowerOfTwo = isPowerOfTwo( renderTarget ); @@ -18456,36 +18560,38 @@ var properties = {}; - return { + function get( object ) { - get: function ( object ) { + var uuid = object.uuid; + var map = properties[ uuid ]; - var uuid = object.uuid; - var map = properties[ uuid ]; + if ( map === undefined ) { - if ( map === undefined ) { - - map = {}; - properties[ uuid ] = map; - - } - - return map; - - }, - - delete: function ( object ) { - - delete properties[ object.uuid ]; - - }, - - clear: function () { - - properties = {}; + map = {}; + properties[ uuid ] = map; } + return map; + + } + + function remove( object ) { + + delete properties[ object.uuid ]; + + } + + function clear() { + + properties = {}; + + } + + return { + get: get, + remove: remove, + clear: clear }; } @@ -18872,7 +18978,7 @@ stencilBuffer.setClear( 0 ); enable( gl.DEPTH_TEST ); - setDepthFunc( LessEqualDepth ); + depthBuffer.setFunc( LessEqualDepth ); setFlipSided( false ); setCullFace( CullFaceBack ); @@ -18915,7 +19021,7 @@ } - function enableAttributeAndDivisor( attribute, meshPerAttribute, extension ) { + function enableAttributeAndDivisor( attribute, meshPerAttribute ) { newAttributes[ attribute ] = 1; @@ -18928,6 +19034,8 @@ if ( attributeDivisors[ attribute ] !== meshPerAttribute ) { + var extension = extensions.get( 'ANGLE_instanced_arrays' ); + extension.vertexAttribDivisorANGLE( attribute, meshPerAttribute ); attributeDivisors[ attribute ] = meshPerAttribute; @@ -19114,53 +19222,24 @@ } - // TODO Deprecate + function setMaterial( material ) { - function setColorWrite( colorWrite ) { + material.side === DoubleSide + ? disable( gl.CULL_FACE ) + : enable( gl.CULL_FACE ); - colorBuffer.setMask( colorWrite ); + setFlipSided( material.side === BackSide ); - } + material.transparent === true + ? setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha ) + : setBlending( NoBlending ); - function setDepthTest( depthTest ) { + depthBuffer.setFunc( material.depthFunc ); + depthBuffer.setTest( material.depthTest ); + depthBuffer.setMask( material.depthWrite ); + colorBuffer.setMask( material.colorWrite ); - depthBuffer.setTest( depthTest ); - - } - - function setDepthWrite( depthWrite ) { - - depthBuffer.setMask( depthWrite ); - - } - - function setDepthFunc( depthFunc ) { - - depthBuffer.setFunc( depthFunc ); - - } - - function setStencilTest( stencilTest ) { - - stencilBuffer.setTest( stencilTest ); - - } - - function setStencilWrite( stencilWrite ) { - - stencilBuffer.setMask( stencilWrite ); - - } - - function setStencilFunc( stencilFunc, stencilRef, stencilMask ) { - - stencilBuffer.setFunc( stencilFunc, stencilRef, stencilMask ); - - } - - function setStencilOp( stencilFail, stencilZFail, stencilZPass ) { - - stencilBuffer.setOp( stencilFail, stencilZFail, stencilZPass ); + setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); } @@ -19423,15 +19502,7 @@ getCompressedTextureFormats: getCompressedTextureFormats, setBlending: setBlending, - - setColorWrite: setColorWrite, - setDepthTest: setDepthTest, - setDepthWrite: setDepthWrite, - setDepthFunc: setDepthFunc, - setStencilTest: setStencilTest, - setStencilWrite: setStencilWrite, - setStencilFunc: setStencilFunc, - setStencilOp: setStencilOp, + setMaterial: setMaterial, setFlipSided: setFlipSided, setCullFace: setCullFace, @@ -19789,6 +19860,7 @@ } + // import { Sphere } from '../math/Sphere'; /** * @author supereggbert / http://www.paulbrunt.co.uk/ * @author mrdoob / http://mrdoob.com/ @@ -19815,10 +19887,7 @@ var lights = []; - var opaqueObjects = []; - var opaqueObjectsLastIndex = - 1; - var transparentObjects = []; - var transparentObjectsLastIndex = - 1; + var currentRenderList = null; var morphInfluences = new Float32Array( 8 ); @@ -19914,8 +19983,6 @@ _clippingEnabled = false, _localClippingEnabled = false, - _sphere = new Sphere(), - // camera matrices cache _projScreenMatrix = new Matrix4(), @@ -19930,18 +19997,18 @@ hash: '', - ambient: [ 0, 0, 0 ], - directional: [], - directionalShadowMap: [], - directionalShadowMatrix: [], - spot: [], - spotShadowMap: [], - spotShadowMatrix: [], - rectArea: [], - point: [], - pointShadowMap: [], - pointShadowMatrix: [], - hemi: [], + ambient: [ 0, 0, 0 ], + directional: [], + directionalShadowMap: [], + directionalShadowMatrix: [], + spot: [], + spotShadowMap: [], + spotShadowMatrix: [], + rectArea: [], + point: [], + pointShadowMap: [], + pointShadowMatrix: [], + hemi: [], shadows: [] @@ -19949,8 +20016,14 @@ // info + _infoMemory = { + geometries: 0, + textures: 0 + }, + _infoRender = { + frame: 0, calls: 0, vertices: 0, faces: 0, @@ -19961,12 +20034,7 @@ this.info = { render: _infoRender, - memory: { - - geometries: 0, - textures: 0 - - }, + memory: _infoMemory, programs: null }; @@ -19978,7 +20046,7 @@ try { - var attributes = { + var contextAttributes = { alpha: _alpha, depth: _depth, stencil: _stencil, @@ -19987,7 +20055,7 @@ preserveDrawingBuffer: _preserveDrawingBuffer }; - _gl = _context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes ); + _gl = _context || _canvas.getContext( 'webgl', contextAttributes ) || _canvas.getContext( 'experimental-webgl', contextAttributes ); if ( _gl === null ) { @@ -20042,11 +20110,15 @@ var capabilities = new WebGLCapabilities( _gl, extensions, parameters ); var state = new WebGLState( _gl, extensions, paramThreeToGL ); + var properties = new WebGLProperties(); - var textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, paramThreeToGL, this.info ); - var objects = new WebGLObjects( _gl, properties, this.info ); + var textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, paramThreeToGL, _infoMemory ); + var attributes = new WebGLAttributes( _gl ); + var geometries = new WebGLGeometries( _gl, attributes, _infoMemory ); + var objects = new WebGLObjects( _gl, geometries, _infoRender ); var programCache = new WebGLPrograms( this, capabilities ); var lightCache = new WebGLLights(); + var renderLists = new WebGLRenderLists(); this.info.programs = programCache.programs; @@ -20125,7 +20197,8 @@ this.forceContextLoss = function () { - extensions.get( 'WEBGL_lose_context' ).loseContext(); + var extension = extensions.get( 'WEBGL_lose_context' ); + if ( extension ) extension.loseContext(); }; @@ -20276,15 +20349,12 @@ this.resetGLState = resetGLState; - this.dispose = function() { - - transparentObjects = []; - transparentObjectsLastIndex = -1; - opaqueObjects = []; - opaqueObjectsLastIndex = -1; + this.dispose = function () { _canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); + renderLists.dispose(); + }; // Events @@ -20297,6 +20367,7 @@ setDefaultGLState(); properties.clear(); + objects.clear(); } @@ -20316,7 +20387,7 @@ releaseMaterialProgramReference( material ); - properties.delete( material ); + properties.remove( material ); } @@ -20337,6 +20408,16 @@ // Buffer rendering + function renderObjectImmediate( object, program, material ) { + + object.render( function ( object ) { + + _this.renderBufferImmediate( object, program, material ); + + } ); + + } + this.renderBufferImmediate = function ( object, program, material ) { state.initAttributes(); @@ -20348,15 +20429,15 @@ if ( object.hasUvs && ! buffers.uv ) buffers.uv = _gl.createBuffer(); if ( object.hasColors && ! buffers.color ) buffers.color = _gl.createBuffer(); - var attributes = program.getAttributes(); + var programAttributes = program.getAttributes(); if ( object.hasPositions ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.position ); _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW ); - state.enableAttribute( attributes.position ); - _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); + state.enableAttribute( programAttributes.position ); + _gl.vertexAttribPointer( programAttributes.position, 3, _gl.FLOAT, false, 0, 0 ); } @@ -20395,9 +20476,9 @@ _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW ); - state.enableAttribute( attributes.normal ); + state.enableAttribute( programAttributes.normal ); - _gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); + _gl.vertexAttribPointer( programAttributes.normal, 3, _gl.FLOAT, false, 0, 0 ); } @@ -20406,7 +20487,7 @@ _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.uv ); _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW ); - state.enableAttribute( attributes.uv ); + state.enableAttribute( programAttributes.uv ); _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); @@ -20417,9 +20498,9 @@ _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.color ); _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW ); - state.enableAttribute( attributes.color ); + state.enableAttribute( programAttributes.color ); - _gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 ); + _gl.vertexAttribPointer( programAttributes.color, 3, _gl.FLOAT, false, 0, 0 ); } @@ -20431,14 +20512,20 @@ }; + function absNumericalSort( a, b ) { + + return Math.abs( b[ 0 ] ) - Math.abs( a[ 0 ] ); + + } + this.renderBufferDirect = function ( camera, fog, geometry, material, object, group ) { - setMaterial( material ); + state.setMaterial( material ); var program = setProgram( camera, fog, material, object ); + var geometryProgram = geometry.id + '_' + program.id + '_' + ( material.wireframe === true ); var updateBuffers = false; - var geometryProgram = geometry.id + '_' + program.id + '_' + material.wireframe; if ( geometryProgram !== _currentGeometryProgram ) { @@ -20453,6 +20540,8 @@ if ( morphTargetInfluences !== undefined ) { + // TODO Remove allocations + var activeInfluences = []; for ( var i = 0, l = morphTargetInfluences.length; i < l; i ++ ) { @@ -20499,8 +20588,7 @@ } - program.getUniforms().setValue( - _gl, 'morphTargetInfluences', morphInfluences ); + program.getUniforms().setValue( _gl, 'morphTargetInfluences', morphInfluences ); updateBuffers = true; @@ -20514,22 +20602,18 @@ if ( material.wireframe === true ) { - index = objects.getWireframeAttribute( geometry ); + index = geometries.getWireframeAttribute( geometry ); rangeFactor = 2; } - var renderer; + var renderer = bufferRenderer; if ( index !== null ) { renderer = indexedBufferRenderer; renderer.setIndex( index ); - } else { - - renderer = bufferRenderer; - } if ( updateBuffers ) { @@ -20538,7 +20622,7 @@ if ( index !== null ) { - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, objects.getAttributeBuffer( index ) ); + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, attributes.get( index ).buffer ); } @@ -20613,6 +20697,10 @@ renderer.setMode( _gl.LINES ); + } else if ( object.isLineLoop ) { + + renderer.setMode( _gl.LINE_LOOP ); + } else { renderer.setMode( _gl.LINE_STRIP ); @@ -20643,13 +20731,9 @@ function setupVertexAttributes( material, program, geometry, startIndex ) { - var extension; - if ( geometry && geometry.isInstancedBufferGeometry ) { - extension = extensions.get( 'ANGLE_instanced_arrays' ); - - if ( extension === null ) { + if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) { console.error( 'THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); return; @@ -20681,9 +20765,9 @@ var normalized = geometryAttribute.normalized; var size = geometryAttribute.itemSize; - var attributeProperties = objects.getAttributeProperties( geometryAttribute ); + var attributeProperties = attributes.get( geometryAttribute ); - var buffer = attributeProperties.__webglBuffer; + var buffer = attributeProperties.buffer; var type = attributeProperties.type; var bytesPerElement = attributeProperties.bytesPerElement; @@ -20695,7 +20779,7 @@ if ( data && data.isInstancedInterleavedBuffer ) { - state.enableAttributeAndDivisor( programAttribute, data.meshPerAttribute, extension ); + state.enableAttributeAndDivisor( programAttribute, data.meshPerAttribute ); if ( geometry.maxInstancedCount === undefined ) { @@ -20716,7 +20800,7 @@ if ( geometryAttribute.isInstancedBufferAttribute ) { - state.enableAttributeAndDivisor( programAttribute, geometryAttribute.meshPerAttribute, extension ); + state.enableAttributeAndDivisor( programAttribute, geometryAttribute.meshPerAttribute ); if ( geometry.maxInstancedCount === undefined ) { @@ -20772,57 +20856,47 @@ } - // Sorting + // Compile - function absNumericalSort( a, b ) { + this.compile = function ( scene, camera ) { - return Math.abs( b[ 0 ] ) - Math.abs( a[ 0 ] ); + lights = []; - } + scene.traverse( function ( object ) { - function painterSortStable( a, b ) { + if ( object.isLight ) { - if ( a.object.renderOrder !== b.object.renderOrder ) { + lights.push( object ); - return a.object.renderOrder - b.object.renderOrder; + } - } else if ( a.material.program && b.material.program && a.material.program !== b.material.program ) { + } ); - return a.material.program.id - b.material.program.id; + setupLights( lights, camera ); - } else if ( a.material.id !== b.material.id ) { + scene.traverse( function ( object ) { - return a.material.id - b.material.id; + if ( object.material ) { - } else if ( a.z !== b.z ) { + if ( Array.isArray( object.material ) ) { - return a.z - b.z; + for ( var i = 0; i < object.material.length; i ++ ) { - } else { + initMaterial( object.material[ i ], scene.fog, object ); - return a.id - b.id; + } - } + } else { - } + initMaterial( object.material, scene.fog, object ); - function reversePainterSortStable( a, b ) { + } - if ( a.object.renderOrder !== b.object.renderOrder ) { + } - return a.object.renderOrder - b.object.renderOrder; + } ); - } if ( a.z !== b.z ) { - - return b.z - a.z; - - } else { - - return a.id - b.id; - - } - - } + }; // Rendering @@ -20847,6 +20921,8 @@ // update camera matrices and frustum + camera.onBeforeRender( _this ); + if ( camera.parent === null ) camera.updateMatrixWorld(); camera.matrixWorldInverse.getInverse( camera.matrixWorld ); @@ -20855,25 +20931,22 @@ _frustum.setFromMatrix( _projScreenMatrix ); lights.length = 0; - - opaqueObjectsLastIndex = - 1; - transparentObjectsLastIndex = - 1; - sprites.length = 0; lensFlares.length = 0; _localClippingEnabled = this.localClippingEnabled; _clippingEnabled = _clipping.init( this.clippingPlanes, _localClippingEnabled, camera ); - projectObject( scene, camera ); + currentRenderList = renderLists.get( scene, camera ); + currentRenderList.init(); - opaqueObjects.length = opaqueObjectsLastIndex + 1; - transparentObjects.length = transparentObjectsLastIndex + 1; + projectObject( scene, camera, _this.sortObjects ); + + currentRenderList.finish(); if ( _this.sortObjects === true ) { - opaqueObjects.sort( painterSortStable ); - transparentObjects.sort( reversePainterSortStable ); + currentRenderList.sort(); } @@ -20891,6 +20964,7 @@ // + _infoRender.frame ++; _infoRender.calls = 0; _infoRender.vertices = 0; _infoRender.faces = 0; @@ -20982,23 +21056,25 @@ // + var opaqueObjects = currentRenderList.opaque; + var transparentObjects = currentRenderList.transparent; + if ( scene.overrideMaterial ) { var overrideMaterial = scene.overrideMaterial; - renderObjects( opaqueObjects, scene, camera, overrideMaterial ); - renderObjects( transparentObjects, scene, camera, overrideMaterial ); + if ( opaqueObjects.length ) renderObjects( opaqueObjects, scene, camera, overrideMaterial ); + if ( transparentObjects.length ) renderObjects( transparentObjects, scene, camera, overrideMaterial ); } else { // opaque pass (front-to-back order) - state.setBlending( NoBlending ); - renderObjects( opaqueObjects, scene, camera ); + if ( opaqueObjects.length ) renderObjects( opaqueObjects, scene, camera ); // transparent pass (back-to-front order) - renderObjects( transparentObjects, scene, camera ); + if ( transparentObjects.length ) renderObjects( transparentObjects, scene, camera ); } @@ -21017,65 +21093,27 @@ // Ensure depth buffer writing is enabled so it can be cleared on next render - state.setDepthTest( true ); - state.setDepthWrite( true ); - state.setColorWrite( true ); + state.buffers.depth.setTest( true ); + state.buffers.depth.setMask( true ); + state.buffers.color.setMask( true ); + + if ( camera.isArrayCamera && camera.enabled ) { + + _this.setScissorTest( false ); + + } + + camera.onAfterRender( _this ); // _gl.finish(); }; - function pushRenderItem( object, geometry, material, z, group ) { - - var array, index; - - // allocate the next position in the appropriate array - - if ( material.transparent ) { - - array = transparentObjects; - index = ++ transparentObjectsLastIndex; - - } else { - - array = opaqueObjects; - index = ++ opaqueObjectsLastIndex; - - } - - // recycle existing render item or grow the array - - var renderItem = array[ index ]; - - if ( renderItem !== undefined ) { - - renderItem.id = object.id; - renderItem.object = object; - renderItem.geometry = geometry; - renderItem.material = material; - renderItem.z = _vector3.z; - renderItem.group = group; - - } else { - - renderItem = { - id: object.id, - object: object, - geometry: geometry, - material: material, - z: _vector3.z, - group: group - }; - - // assert( index === array.length ); - array.push( renderItem ); - - } - - } - + /* // TODO Duplicated code (Frustum) + var _sphere = new Sphere(); + function isObjectViewable( object ) { var geometry = object.geometry; @@ -21124,12 +21162,13 @@ return true; } + */ - function projectObject( object, camera ) { + function projectObject( object, camera, sortObjects ) { - if ( object.visible === false ) return; + if ( ! object.visible ) return; - var visible = ( object.layers.mask & camera.layers.mask ) !== 0; + var visible = object.layers.test( camera.layers ); if ( visible ) { @@ -21139,7 +21178,7 @@ } else if ( object.isSprite ) { - if ( object.frustumCulled === false || isSpriteViewable( object ) === true ) { + if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) { sprites.push( object ); @@ -21151,14 +21190,14 @@ } else if ( object.isImmediateRenderObject ) { - if ( _this.sortObjects === true ) { + if ( sortObjects ) { - _vector3.setFromMatrixPosition( object.matrixWorld ); - _vector3.applyMatrix4( _projScreenMatrix ); + _vector3.setFromMatrixPosition( object.matrixWorld ) + .applyMatrix4( _projScreenMatrix ); } - pushRenderItem( object, null, object.material, _vector3.z, null ); + currentRenderList.push( object, null, object.material, _vector3.z, null ); } else if ( object.isMesh || object.isLine || object.isPoints ) { @@ -21168,45 +21207,39 @@ } - if ( object.frustumCulled === false || isObjectViewable( object ) === true ) { + if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) { + if ( sortObjects ) { + + _vector3.setFromMatrixPosition( object.matrixWorld ) + .applyMatrix4( _projScreenMatrix ); + + } + + var geometry = objects.update( object ); var material = object.material; - if ( material.visible === true ) { + if ( Array.isArray( material ) ) { - if ( _this.sortObjects === true ) { + var groups = geometry.groups; - _vector3.setFromMatrixPosition( object.matrixWorld ); - _vector3.applyMatrix4( _projScreenMatrix ); + for ( var i = 0, l = groups.length; i < l; i ++ ) { - } + var group = groups[ i ]; + var groupMaterial = material[ group.materialIndex ]; - var geometry = objects.update( object ); + if ( groupMaterial && groupMaterial.visible ) { - if ( material.isMultiMaterial ) { - - var groups = geometry.groups; - var materials = material.materials; - - for ( var i = 0, l = groups.length; i < l; i ++ ) { - - var group = groups[ i ]; - var groupMaterial = materials[ group.materialIndex ]; - - if ( groupMaterial.visible === true ) { - - pushRenderItem( object, geometry, groupMaterial, _vector3.z, group ); - - } + currentRenderList.push( object, geometry, groupMaterial, _vector3.z, group ); } - } else { - - pushRenderItem( object, geometry, material, _vector3.z, null ); - } + } else if ( material.visible ) { + + currentRenderList.push( object, geometry, material, _vector3.z, null ); + } } @@ -21219,7 +21252,7 @@ for ( var i = 0, l = children.length; i < l; i ++ ) { - projectObject( children[ i ], camera ); + projectObject( children[ i ], camera, sortObjects ); } @@ -21236,33 +21269,61 @@ var material = overrideMaterial === undefined ? renderItem.material : overrideMaterial; var group = renderItem.group; - object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); - object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); - object.onBeforeRender( _this, scene, camera, geometry, material, group ); - if ( object.isImmediateRenderObject ) { + if ( camera.isArrayCamera && camera.enabled ) { - setMaterial( material ); + var cameras = camera.cameras; - var program = setProgram( camera, scene.fog, material, object ); + for ( var j = 0, jl = cameras.length; j < jl; j ++ ) { - _currentGeometryProgram = ''; + var camera2 = cameras[ j ]; + var bounds = camera2.bounds; - object.render( function ( object ) { + _this.setViewport( + bounds.x * _width * _pixelRatio, bounds.y * _height * _pixelRatio, + bounds.z * _width * _pixelRatio, bounds.w * _height * _pixelRatio + ); + _this.setScissor( + bounds.x * _width * _pixelRatio, bounds.y * _height * _pixelRatio, + bounds.z * _width * _pixelRatio, bounds.w * _height * _pixelRatio + ); + _this.setScissorTest( true ); - _this.renderBufferImmediate( object, program, material ); + renderObject( object, scene, camera2, geometry, material, group ); - } ); + } } else { - _this.renderBufferDirect( camera, scene.fog, geometry, material, object, group ); + renderObject( object, scene, camera, geometry, material, group ); } object.onAfterRender( _this, scene, camera, geometry, material, group ); + } + + } + + function renderObject( object, scene, camera, geometry, material, group ) { + + object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); + + if ( object.isImmediateRenderObject ) { + + state.setMaterial( material ); + + var program = setProgram( camera, scene.fog, material, object ); + + _currentGeometryProgram = ''; + + renderObjectImmediate( object, program, material ); + + } else { + + _this.renderBufferDirect( camera, scene.fog, geometry, material, object, group ); } @@ -21335,7 +21396,7 @@ } - var attributes = program.getAttributes(); + var programAttributes = program.getAttributes(); if ( material.morphTargets ) { @@ -21343,7 +21404,7 @@ for ( var i = 0; i < _this.maxMorphTargets; i ++ ) { - if ( attributes[ 'morphTarget' + i ] >= 0 ) { + if ( programAttributes[ 'morphTarget' + i ] >= 0 ) { material.numSupportedMorphTargets ++; @@ -21359,7 +21420,7 @@ for ( var i = 0; i < _this.maxMorphNormals; i ++ ) { - if ( attributes[ 'morphNormal' + i ] >= 0 ) { + if ( programAttributes[ 'morphNormal' + i ] >= 0 ) { material.numSupportedMorphNormals ++; @@ -21416,26 +21477,6 @@ } - function setMaterial( material ) { - - material.side === DoubleSide - ? state.disable( _gl.CULL_FACE ) - : state.enable( _gl.CULL_FACE ); - - state.setFlipSided( material.side === BackSide ); - - material.transparent === true - ? state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha ) - : state.setBlending( NoBlending ); - - state.setDepthFunc( material.depthFunc ); - state.setDepthTest( material.depthTest ); - state.setDepthWrite( material.depthWrite ); - state.setColorWrite( material.colorWrite ); - state.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); - - } - function setProgram( camera, fog, material, object ) { _usedTextureUnits = 0; @@ -21477,7 +21518,7 @@ } else if ( materialProperties.numClippingPlanes !== undefined && ( materialProperties.numClippingPlanes !== _clipping.numPlanes || - materialProperties.numIntersection !== _clipping.numIntersection ) ) { + materialProperties.numIntersection !== _clipping.numIntersection ) ) { material.needsUpdate = true; @@ -21521,7 +21562,7 @@ if ( refreshProgram || camera !== _currentCamera ) { - p_uniforms.set( _gl, camera, 'projectionMatrix' ); + p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); if ( capabilities.logarithmicDepthBuffer ) { @@ -21574,8 +21615,8 @@ } - p_uniforms.set( _gl, _this, 'toneMappingExposure' ); - p_uniforms.set( _gl, _this, 'toneMappingWhitePoint' ); + p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure ); + p_uniforms.setValue( _gl, 'toneMappingWhitePoint', _this.toneMappingWhitePoint ); } @@ -21592,11 +21633,37 @@ if ( skeleton ) { - if ( capabilities.floatVertexTextures && skeleton.useVertexTexture ) { + var bones = skeleton.bones; - p_uniforms.set( _gl, skeleton, 'boneTexture' ); - p_uniforms.set( _gl, skeleton, 'boneTextureWidth' ); - p_uniforms.set( _gl, skeleton, 'boneTextureHeight' ); + if ( capabilities.floatVertexTextures ) { + + if ( skeleton.boneTexture === undefined ) { + + // layout (1 matrix = 4 pixels) + // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) + // with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8) + // 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16) + // 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32) + // 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64) + + + var size = Math.sqrt( bones.length * 4 ); // 4 pixels needed for 1 matrix + size = _Math.nextPowerOfTwo( Math.ceil( size ) ); + size = Math.max( size, 4 ); + + var boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel + boneMatrices.set( skeleton.boneMatrices ); // copy current values + + var boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType ); + + skeleton.boneMatrices = boneMatrices; + skeleton.boneTexture = boneTexture; + skeleton.boneTextureSize = size; + + } + + p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture ); + p_uniforms.setValue( _gl, 'boneTextureSize', skeleton.boneTextureSize ); } else { @@ -21698,8 +21765,8 @@ // RectAreaLight Texture // TODO (mrdoob): Find a nicer implementation - if ( m_uniforms.ltcMat !== undefined ) m_uniforms.ltcMat.value = THREE.UniformsLib.LTC_MAT_TEXTURE; - if ( m_uniforms.ltcMag !== undefined ) m_uniforms.ltcMag.value = THREE.UniformsLib.LTC_MAG_TEXTURE; + if ( m_uniforms.ltcMat !== undefined ) m_uniforms.ltcMat.value = UniformsLib.LTC_MAT_TEXTURE; + if ( m_uniforms.ltcMag !== undefined ) m_uniforms.ltcMag.value = UniformsLib.LTC_MAG_TEXTURE; WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, _this ); @@ -21709,8 +21776,8 @@ // common matrices - p_uniforms.set( _gl, object, 'modelViewMatrix' ); - p_uniforms.set( _gl, object, 'normalMatrix' ); + p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix ); + p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix ); p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld ); return program; @@ -22050,7 +22117,8 @@ if ( light.castShadow ) { - _lights.shadows[ lightShadowsLength ++ ] = light; + _lights.shadows[ lightShadowsLength ] = light; + lightShadowsLength ++; } @@ -22062,7 +22130,7 @@ function setupLights( lights, camera ) { - var l, ll, light, + var l, ll, light, shadow, r = 0, g = 0, b = 0, color, intensity, @@ -22071,11 +22139,11 @@ viewMatrix = camera.matrixWorldInverse, - directionalLength = 0, - pointLength = 0, - spotLength = 0, - rectAreaLength = 0, - hemiLength = 0; + directionalLength = 0, + pointLength = 0, + spotLength = 0, + rectAreaLength = 0, + hemiLength = 0; for ( l = 0, ll = lights.length; l < ll; l ++ ) { @@ -22107,15 +22175,19 @@ if ( light.castShadow ) { - uniforms.shadowBias = light.shadow.bias; - uniforms.shadowRadius = light.shadow.radius; - uniforms.shadowMapSize = light.shadow.mapSize; + shadow = light.shadow; + + uniforms.shadowBias = shadow.bias; + uniforms.shadowRadius = shadow.radius; + uniforms.shadowMapSize = shadow.mapSize; } _lights.directionalShadowMap[ directionalLength ] = shadowMap; _lights.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix; - _lights.directional[ directionalLength ++ ] = uniforms; + _lights.directional[ directionalLength ] = uniforms; + + directionalLength ++; } else if ( light.isSpotLight ) { @@ -22140,15 +22212,19 @@ if ( light.castShadow ) { - uniforms.shadowBias = light.shadow.bias; - uniforms.shadowRadius = light.shadow.radius; - uniforms.shadowMapSize = light.shadow.mapSize; + shadow = light.shadow; + + uniforms.shadowBias = shadow.bias; + uniforms.shadowRadius = shadow.radius; + uniforms.shadowMapSize = shadow.mapSize; } _lights.spotShadowMap[ spotLength ] = shadowMap; _lights.spotShadowMatrix[ spotLength ] = light.shadow.matrix; - _lights.spot[ spotLength ++ ] = uniforms; + _lights.spot[ spotLength ] = uniforms; + + spotLength ++; } else if ( light.isRectAreaLight ) { @@ -22180,7 +22256,9 @@ // TODO (abelnation): RectAreaLight distance? // uniforms.distance = distance; - _lights.rectArea[ rectAreaLength ++ ] = uniforms; + _lights.rectArea[ rectAreaLength ] = uniforms; + + rectAreaLength ++; } else if ( light.isPointLight ) { @@ -22197,26 +22275,19 @@ if ( light.castShadow ) { - uniforms.shadowBias = light.shadow.bias; - uniforms.shadowRadius = light.shadow.radius; - uniforms.shadowMapSize = light.shadow.mapSize; + shadow = light.shadow; + + uniforms.shadowBias = shadow.bias; + uniforms.shadowRadius = shadow.radius; + uniforms.shadowMapSize = shadow.mapSize; } _lights.pointShadowMap[ pointLength ] = shadowMap; + _lights.pointShadowMatrix[ pointLength ] = light.shadow.matrix; + _lights.point[ pointLength ] = uniforms; - if ( _lights.pointShadowMatrix[ pointLength ] === undefined ) { - - _lights.pointShadowMatrix[ pointLength ] = new Matrix4(); - - } - - // for point lights we set the shadow matrix to be a translation-only matrix - // equal to inverse of the light's position - _vector3.setFromMatrixPosition( light.matrixWorld ).negate(); - _lights.pointShadowMatrix[ pointLength ].identity().setPosition( _vector3 ); - - _lights.point[ pointLength ++ ] = uniforms; + pointLength ++; } else if ( light.isHemisphereLight ) { @@ -22229,7 +22300,9 @@ uniforms.skyColor.copy( light.color ).multiplyScalar( intensity ); uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity ); - _lights.hemi[ hemiLength ++ ] = uniforms; + _lights.hemi[ hemiLength ] = uniforms; + + hemiLength ++; } @@ -22280,7 +22353,7 @@ this.allocTextureUnit = allocTextureUnit; // this.setTexture2D = setTexture2D; - this.setTexture2D = ( function() { + this.setTexture2D = ( function () { var warned = false; @@ -22306,7 +22379,7 @@ }() ); - this.setTexture = ( function() { + this.setTexture = ( function () { var warned = false; @@ -22325,7 +22398,7 @@ }() ); - this.setTextureCube = ( function() { + this.setTextureCube = ( function () { var warned = false; @@ -22367,7 +22440,7 @@ }() ); - this.getCurrentRenderTarget = function() { + this.getRenderTarget = function () { return _currentRenderTarget; @@ -22727,35 +22800,37 @@ } - Scene.prototype = Object.create( Object3D.prototype ); + Scene.prototype = Object.assign( Object.create( Object3D.prototype ), { - Scene.prototype.constructor = Scene; + constructor: Scene, - Scene.prototype.copy = function ( source, recursive ) { + copy: function ( source, recursive ) { - Object3D.prototype.copy.call( this, source, recursive ); + Object3D.prototype.copy.call( this, source, recursive ); - if ( source.background !== null ) this.background = source.background.clone(); - if ( source.fog !== null ) this.fog = source.fog.clone(); - if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone(); + if ( source.background !== null ) this.background = source.background.clone(); + if ( source.fog !== null ) this.fog = source.fog.clone(); + if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone(); - this.autoUpdate = source.autoUpdate; - this.matrixAutoUpdate = source.matrixAutoUpdate; + this.autoUpdate = source.autoUpdate; + this.matrixAutoUpdate = source.matrixAutoUpdate; - return this; + return this; - }; + }, - Scene.prototype.toJSON = function ( meta ) { + toJSON: function ( meta ) { - var data = Object3D.prototype.toJSON.call( this, meta ); + var data = Object3D.prototype.toJSON.call( this, meta ); - if ( this.background !== null ) data.object.background = this.background.toJSON( meta ); - if ( this.fog !== null ) data.object.fog = this.fog.toJSON(); + if ( this.background !== null ) data.object.background = this.background.toJSON( meta ); + if ( this.fog !== null ) data.object.fog = this.fog.toJSON(); - return data; + return data; - }; + } + + } ); /** * @author mikael emtinger / http://gomo.se/ @@ -22887,6 +22962,7 @@ SpriteMaterial.prototype = Object.create( Material.prototype ); SpriteMaterial.prototype.constructor = SpriteMaterial; + SpriteMaterial.prototype.isSpriteMaterial = true; SpriteMaterial.prototype.copy = function ( source ) { @@ -22924,25 +23000,28 @@ raycast: ( function () { - var matrixPosition = new Vector3(); + var intersectPoint = new Vector3(); + var worldPosition = new Vector3(); + var worldScale = new Vector3(); return function raycast( raycaster, intersects ) { - matrixPosition.setFromMatrixPosition( this.matrixWorld ); + worldPosition.setFromMatrixPosition( this.matrixWorld ); + raycaster.ray.closestPointToPoint( worldPosition, intersectPoint ); - var distanceSq = raycaster.ray.distanceSqToPoint( matrixPosition ); - var guessSizeSq = this.scale.x * this.scale.y / 4; + worldScale.setFromMatrixScale( this.matrixWorld ); + var guessSizeSq = worldScale.x * worldScale.y / 4; - if ( distanceSq > guessSizeSq ) { + if ( worldPosition.distanceToSquared( intersectPoint ) > guessSizeSq ) return; - return; + var distance = raycaster.ray.origin.distanceTo( intersectPoint ); - } + if ( distance < raycaster.near || distance > raycaster.far ) return; intersects.push( { - distance: Math.sqrt( distanceSq ), - point: this.position, + distance: distance, + point: intersectPoint.clone(), face: null, object: this @@ -22981,7 +23060,6 @@ } - LOD.prototype = Object.assign( Object.create( Object3D.prototype ), { constructor: LOD, @@ -23139,45 +23217,14 @@ * @author ikerr / http://verold.com */ - function Skeleton( bones, boneInverses, useVertexTexture ) { - - this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true; - - this.identityMatrix = new Matrix4(); + function Skeleton( bones, boneInverses ) { // copy the bone array bones = bones || []; this.bones = bones.slice( 0 ); - - // create a bone texture or an array of floats - - if ( this.useVertexTexture ) { - - // layout (1 matrix = 4 pixels) - // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) - // with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8) - // 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16) - // 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32) - // 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64) - - - var size = Math.sqrt( this.bones.length * 4 ); // 4 pixels needed for 1 matrix - size = _Math.nextPowerOfTwo( Math.ceil( size ) ); - size = Math.max( size, 4 ); - - this.boneTextureWidth = size; - this.boneTextureHeight = size; - - this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel - this.boneTexture = new DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, RGBAFormat, FloatType ); - - } else { - - this.boneMatrices = new Float32Array( 16 * this.bones.length ); - - } + this.boneMatrices = new Float32Array( this.bones.length * 16 ); // use the supplied bone inverses or calculate the inverses @@ -23193,11 +23240,11 @@ } else { - console.warn( 'THREE.Skeleton bonInverses is the wrong length.' ); + console.warn( 'THREE.Skeleton boneInverses is the wrong length.' ); this.boneInverses = []; - for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { + for ( var i = 0, il = this.bones.length; i < il; i ++ ) { this.boneInverses.push( new Matrix4() ); @@ -23215,13 +23262,13 @@ this.boneInverses = []; - for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { + for ( var i = 0, il = this.bones.length; i < il; i ++ ) { var inverse = new Matrix4(); - if ( this.bones[ b ] ) { + if ( this.bones[ i ] ) { - inverse.getInverse( this.bones[ b ].matrixWorld ); + inverse.getInverse( this.bones[ i ].matrixWorld ); } @@ -23233,17 +23280,17 @@ pose: function () { - var bone; + var bone, i, il; // recover the bind-time world matrices - for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { + for ( i = 0, il = this.bones.length; i < il; i ++ ) { - bone = this.bones[ b ]; + bone = this.bones[ i ]; if ( bone ) { - bone.matrixWorld.getInverse( this.boneInverses[ b ] ); + bone.matrixWorld.getInverse( this.boneInverses[ i ] ); } @@ -23251,9 +23298,9 @@ // compute the local matrices, positions, rotations and scales - for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { + for ( i = 0, il = this.bones.length; i < il; i ++ ) { - bone = this.bones[ b ]; + bone = this.bones[ i ]; if ( bone ) { @@ -23279,25 +23326,31 @@ update: ( function () { var offsetMatrix = new Matrix4(); + var identityMatrix = new Matrix4(); return function update() { + var bones = this.bones; + var boneInverses = this.boneInverses; + var boneMatrices = this.boneMatrices; + var boneTexture = this.boneTexture; + // flatten bone matrices to array - for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { + for ( var i = 0, il = bones.length; i < il; i ++ ) { // compute the offset between the current and the original transform - var matrix = this.bones[ b ] ? this.bones[ b ].matrixWorld : this.identityMatrix; + var matrix = bones[ i ] ? bones[ i ].matrixWorld : identityMatrix; - offsetMatrix.multiplyMatrices( matrix, this.boneInverses[ b ] ); - offsetMatrix.toArray( this.boneMatrices, b * 16 ); + offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] ); + offsetMatrix.toArray( boneMatrices, i * 16 ); } - if ( this.useVertexTexture ) { + if ( boneTexture !== undefined ) { - this.boneTexture.needsUpdate = true; + boneTexture.needsUpdate = true; } @@ -23307,7 +23360,7 @@ clone: function () { - return new Skeleton( this.bones, this.boneInverses, this.useVertexTexture ); + return new Skeleton( this.bones, this.boneInverses ); } @@ -23341,75 +23394,92 @@ * @author ikerr / http://verold.com */ - function SkinnedMesh( geometry, material, useVertexTexture ) { + function SkinnedMesh( geometry, material ) { Mesh.call( this, geometry, material ); this.type = 'SkinnedMesh'; - this.bindMode = "attached"; + this.bindMode = 'attached'; this.bindMatrix = new Matrix4(); this.bindMatrixInverse = new Matrix4(); - // init bones + var bones = this.initBones(); + var skeleton = new Skeleton( bones ); - // TODO: remove bone creation as there is no reason (other than - // convenience) for THREE.SkinnedMesh to do this. - - var bones = []; - - if ( this.geometry && this.geometry.bones !== undefined ) { - - var bone, gbone; - - for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) { - - gbone = this.geometry.bones[ b ]; - - bone = new Bone(); - bones.push( bone ); - - bone.name = gbone.name; - bone.position.fromArray( gbone.pos ); - bone.quaternion.fromArray( gbone.rotq ); - if ( gbone.scl !== undefined ) bone.scale.fromArray( gbone.scl ); - - } - - for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) { - - gbone = this.geometry.bones[ b ]; - - if ( gbone.parent !== - 1 && gbone.parent !== null && - bones[ gbone.parent ] !== undefined ) { - - bones[ gbone.parent ].add( bones[ b ] ); - - } else { - - this.add( bones[ b ] ); - - } - - } - - } + this.bind( skeleton, this.matrixWorld ); this.normalizeSkinWeights(); - this.updateMatrixWorld( true ); - this.bind( new Skeleton( bones, undefined, useVertexTexture ), this.matrixWorld ); - } - SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), { constructor: SkinnedMesh, isSkinnedMesh: true, - bind: function( skeleton, bindMatrix ) { + initBones: function () { + + var bones = [], bone, gbone; + var i, il; + + if ( this.geometry && this.geometry.bones !== undefined ) { + + // first, create array of 'Bone' objects from geometry data + + for ( i = 0, il = this.geometry.bones.length; i < il; i ++ ) { + + gbone = this.geometry.bones[ i ]; + + // create new 'Bone' object + + bone = new Bone(); + bones.push( bone ); + + // apply values + + bone.name = gbone.name; + bone.position.fromArray( gbone.pos ); + bone.quaternion.fromArray( gbone.rotq ); + if ( gbone.scl !== undefined ) bone.scale.fromArray( gbone.scl ); + + } + + // second, create bone hierarchy + + for ( i = 0, il = this.geometry.bones.length; i < il; i ++ ) { + + gbone = this.geometry.bones[ i ]; + + if ( ( gbone.parent !== - 1 ) && ( gbone.parent !== null ) && ( bones[ gbone.parent ] !== undefined ) ) { + + // subsequent bones in the hierarchy + + bones[ gbone.parent ].add( bones[ i ] ); + + } else { + + // topmost bone, immediate child of the skinned mesh + + this.add( bones[ i ] ); + + } + + } + + } + + // now the bones are part of the scene graph and children of the skinned mesh. + // let's update the corresponding matrices + + this.updateMatrixWorld( true ); + + return bones; + + }, + + bind: function ( skeleton, bindMatrix ) { this.skeleton = skeleton; @@ -23436,13 +23506,15 @@ normalizeSkinWeights: function () { + var scale, i; + if ( this.geometry && this.geometry.isGeometry ) { - for ( var i = 0; i < this.geometry.skinWeights.length; i ++ ) { + for ( i = 0; i < this.geometry.skinWeights.length; i ++ ) { var sw = this.geometry.skinWeights[ i ]; - var scale = 1.0 / sw.lengthManhattan(); + scale = 1.0 / sw.lengthManhattan(); if ( scale !== Infinity ) { @@ -23462,14 +23534,14 @@ var skinWeight = this.geometry.attributes.skinWeight; - for ( var i = 0; i < skinWeight.count; i ++ ) { + for ( i = 0; i < skinWeight.count; i ++ ) { vec.x = skinWeight.getX( i ); vec.y = skinWeight.getY( i ); vec.z = skinWeight.getZ( i ); vec.w = skinWeight.getW( i ); - var scale = 1.0 / vec.lengthManhattan(); + scale = 1.0 / vec.lengthManhattan(); if ( scale !== Infinity ) { @@ -23489,29 +23561,29 @@ }, - updateMatrixWorld: function( force ) { + updateMatrixWorld: function ( force ) { - Mesh.prototype.updateMatrixWorld.call( this, true ); + Mesh.prototype.updateMatrixWorld.call( this, force ); - if ( this.bindMode === "attached" ) { + if ( this.bindMode === 'attached' ) { this.bindMatrixInverse.getInverse( this.matrixWorld ); - } else if ( this.bindMode === "detached" ) { + } else if ( this.bindMode === 'detached' ) { this.bindMatrixInverse.getInverse( this.bindMatrix ); } else { - console.warn( 'THREE.SkinnedMesh unrecognized bindMode: ' + this.bindMode ); + console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode ); } }, - clone: function() { + clone: function () { - return new this.constructor( this.geometry, this.material, this.skeleton.useVertexTexture ).copy( this ); + return new this.constructor( this.geometry, this.material ).copy( this ); } @@ -23773,6 +23845,26 @@ } ); + /** + * @author mgreter / http://github.com/mgreter + */ + + function LineLoop( geometry, material ) { + + Line.call( this, geometry, material ); + + this.type = 'LineLoop'; + + } + + LineLoop.prototype = Object.assign( Object.create( Line.prototype ), { + + constructor: LineLoop, + + isLineLoop: true, + + } ); + /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ @@ -23866,6 +23958,7 @@ sphere.copy( geometry.boundingSphere ); sphere.applyMatrix4( matrixWorld ); + sphere.radius += threshold; if ( raycaster.ray.intersectsSphere( sphere ) === false ) return; @@ -24106,7 +24199,7 @@ // helper variables var i, j, l, o, ol; - var edge = [ 0, 0 ], edges = {}, e; + var edge = [ 0, 0 ], edges = {}, e, edge1, edge2; var key, keys = [ 'a', 'b', 'c' ]; var vertex; @@ -24124,11 +24217,12 @@ for ( j = 0; j < 3; j ++ ) { - edge[ 0 ] = face[ keys[ j ] ]; - edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ]; - edge.sort( sortFunction ); // sorting prevents duplicates + edge1 = face[ keys[ j ] ]; + edge2 = face[ keys[ ( j + 1 ) % 3 ] ]; + edge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates + edge[ 1 ] = Math.max( edge1, edge2 ); - key = edge.toString(); + key = edge[ 0 ] + ',' + edge[ 1 ]; if ( edges[ key ] === undefined ) { @@ -24172,7 +24266,7 @@ if ( groups.length === 0 ) { - geometry.addGroup( 0, indices.count ); + groups = [ { start: 0, count: indices.count, materialIndex: 0 } ]; } @@ -24189,11 +24283,12 @@ for ( j = 0; j < 3; j ++ ) { - edge[ 0 ] = indices.getX( i + j ); - edge[ 1 ] = indices.getX( i + ( j + 1 ) % 3 ); - edge.sort( sortFunction ); // sorting prevents duplicates + edge1 = indices.getX( i + j ); + edge2 = indices.getX( i + ( j + 1 ) % 3 ); + edge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates + edge[ 1 ] = Math.max( edge1, edge2 ); - key = edge.toString(); + key = edge[ 0 ] + ',' + edge[ 1 ]; if ( edges[ key ] === undefined ) { @@ -24254,14 +24349,6 @@ this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - // custom array sort function - - function sortFunction( a, b ) { - - return a - b; - - } - } WireframeGeometry.prototype = Object.create( BufferGeometry.prototype ); @@ -24269,11 +24356,14 @@ /** * @author zz85 / https://github.com/zz85 + * @author Mugen87 / https://github.com/Mugen87 * * Parametric Surfaces Geometry * based on the brilliant article by @prideout http://prideout.net/blog/?p=44 */ + // ParametricGeometry + function ParametricGeometry( func, slices, stacks ) { Geometry.call( this ); @@ -24294,12 +24384,7 @@ ParametricGeometry.prototype = Object.create( Geometry.prototype ); ParametricGeometry.prototype.constructor = ParametricGeometry; - /** - * @author Mugen87 / https://github.com/Mugen87 - * - * Parametric Surfaces Geometry - * based on the brilliant article by @prideout http://prideout.net/blog/?p=44 - */ + // ParametricBufferGeometry function ParametricBufferGeometry( func, slices, stacks ) { @@ -24317,11 +24402,19 @@ var indices = []; var vertices = []; + var normals = []; var uvs = []; + var EPS = 0.00001; + + var normal = new Vector3(); + + var p0 = new Vector3(), p1 = new Vector3(); + var pu = new Vector3(), pv = new Vector3(); + var i, j; - // generate vertices and uvs + // generate vertices, normals and uvs var sliceCount = slices + 1; @@ -24333,8 +24426,45 @@ var u = j / slices; - var p = func( u, v ); - vertices.push( p.x, p.y, p.z ); + // vertex + + p0 = func( u, v, p0 ); + vertices.push( p0.x, p0.y, p0.z ); + + // normal + + // approximate tangent vectors via finite differences + + if ( u - EPS >= 0 ) { + + p1 = func( u - EPS, v, p1 ); + pu.subVectors( p0, p1 ); + + } else { + + p1 = func( u + EPS, v, p1 ); + pu.subVectors( p1, p0 ); + + } + + if ( v - EPS >= 0 ) { + + p1 = func( u, v - EPS, p1 ); + pv.subVectors( p0, p1 ); + + } else { + + p1 = func( u, v + EPS, p1 ); + pv.subVectors( p1, p0 ); + + } + + // cross product of tangent vectors returns surface normal + + normal.crossVectors( pu, pv ).normalize(); + normals.push( normal.x, normal.y, normal.z ); + + // uv uvs.push( u, v ); @@ -24366,12 +24496,9 @@ this.setIndex( indices ); this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - // generate normals - - this.computeVertexNormals(); - } ParametricBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); @@ -24381,7 +24508,10 @@ * @author clockworkgeek / https://github.com/clockworkgeek * @author timothypratley / https://github.com/timothypratley * @author WestLangley / http://github.com/WestLangley - */ + * @author Mugen87 / https://github.com/Mugen87 + */ + + // PolyhedronGeometry function PolyhedronGeometry( vertices, indices, radius, detail ) { @@ -24404,9 +24534,7 @@ PolyhedronGeometry.prototype = Object.create( Geometry.prototype ); PolyhedronGeometry.prototype.constructor = PolyhedronGeometry; - /** - * @author Mugen87 / https://github.com/Mugen87 - */ + // PolyhedronBufferGeometry function PolyhedronBufferGeometry( vertices, indices, radius, detail ) { @@ -24702,8 +24830,11 @@ /** * @author timothypratley / https://github.com/timothypratley + * @author Mugen87 / https://github.com/Mugen87 */ + // TetrahedronGeometry + function TetrahedronGeometry( radius, detail ) { Geometry.call( this ); @@ -24723,9 +24854,7 @@ TetrahedronGeometry.prototype = Object.create( Geometry.prototype ); TetrahedronGeometry.prototype.constructor = TetrahedronGeometry; - /** - * @author Mugen87 / https://github.com/Mugen87 - */ + // TetrahedronBufferGeometry function TetrahedronBufferGeometry( radius, detail ) { @@ -24753,8 +24882,11 @@ /** * @author timothypratley / https://github.com/timothypratley + * @author Mugen87 / https://github.com/Mugen87 */ + // OctahedronGeometry + function OctahedronGeometry( radius, detail ) { Geometry.call( this ); @@ -24774,9 +24906,7 @@ OctahedronGeometry.prototype = Object.create( Geometry.prototype ); OctahedronGeometry.prototype.constructor = OctahedronGeometry; - /** - * @author Mugen87 / https://github.com/Mugen87 - */ + // OctahedronBufferGeometry function OctahedronBufferGeometry( radius, detail ) { @@ -24804,8 +24934,11 @@ /** * @author timothypratley / https://github.com/timothypratley + * @author Mugen87 / https://github.com/Mugen87 */ + // IcosahedronGeometry + function IcosahedronGeometry( radius, detail ) { Geometry.call( this ); @@ -24825,9 +24958,7 @@ IcosahedronGeometry.prototype = Object.create( Geometry.prototype ); IcosahedronGeometry.prototype.constructor = IcosahedronGeometry; - /** - * @author Mugen87 / https://github.com/Mugen87 - */ + // IcosahedronBufferGeometry function IcosahedronBufferGeometry( radius, detail ) { @@ -24862,8 +24993,11 @@ /** * @author Abe Pazos / https://hamoid.com + * @author Mugen87 / https://github.com/Mugen87 */ + // DodecahedronGeometry + function DodecahedronGeometry( radius, detail ) { Geometry.call( this ); @@ -24883,9 +25017,7 @@ DodecahedronGeometry.prototype = Object.create( Geometry.prototype ); DodecahedronGeometry.prototype.constructor = DodecahedronGeometry; - /** - * @author Mugen87 / https://github.com/Mugen87 - */ + // DodecahedronBufferGeometry function DodecahedronBufferGeometry( radius, detail ) { @@ -24948,10 +25080,12 @@ * @author zz85 / https://github.com/zz85 * @author miningold / https://github.com/miningold * @author jonobr1 / https://github.com/jonobr1 + * @author Mugen87 / https://github.com/Mugen87 * - * Creates a tube which extrudes along a 3d spline. */ + // TubeGeometry + function TubeGeometry( path, tubularSegments, radius, radialSegments, closed, taper ) { Geometry.call( this ); @@ -24986,9 +25120,7 @@ TubeGeometry.prototype = Object.create( Geometry.prototype ); TubeGeometry.prototype.constructor = TubeGeometry; - /** - * @author Mugen87 / https://github.com/Mugen87 - */ + // TubeBufferGeometry function TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ) { @@ -25158,8 +25290,13 @@ /** * @author oosmoxiecode + * @author Mugen87 / https://github.com/Mugen87 + * + * based on http://www.blackpawn.com/texts/pqtorus/ */ + // TorusKnotGeometry + function TorusKnotGeometry( radius, tube, tubularSegments, radialSegments, p, q, heightScale ) { Geometry.call( this ); @@ -25185,10 +25322,7 @@ TorusKnotGeometry.prototype = Object.create( Geometry.prototype ); TorusKnotGeometry.prototype.constructor = TorusKnotGeometry; - /** - * @author Mugen87 / https://github.com/Mugen87 - * see: http://www.blackpawn.com/texts/pqtorus/ - */ + // TorusKnotBufferGeometry function TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) { @@ -25225,7 +25359,6 @@ var vertex = new Vector3(); var normal = new Vector3(); - var uv = new Vector2(); var P1 = new Vector3(); var P2 = new Vector3(); @@ -25345,9 +25478,11 @@ /** * @author oosmoxiecode * @author mrdoob / http://mrdoob.com/ - * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3DLite/src/away3dlite/primitives/Torus.as?r=2888 + * @author Mugen87 / https://github.com/Mugen87 */ + // TorusGeometry + function TorusGeometry( radius, tube, radialSegments, tubularSegments, arc ) { Geometry.call( this ); @@ -25363,15 +25498,14 @@ }; this.fromBufferGeometry( new TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) ); + this.mergeVertices(); } TorusGeometry.prototype = Object.create( Geometry.prototype ); TorusGeometry.prototype.constructor = TorusGeometry; - /** - * @author Mugen87 / https://github.com/Mugen87 - */ + // TorusBufferGeometry function TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) { @@ -26188,29 +26322,52 @@ * extrudePath: // curve to extrude shape along * frames: // containing arrays of tangents, normals, binormals * - * uvGenerator: // object that provides UV generator functions + * UVGenerator: // object that provides UV generator functions * * } - **/ + */ + + // ExtrudeGeometry function ExtrudeGeometry( shapes, options ) { - if ( typeof( shapes ) === "undefined" ) { + Geometry.call( this ); + + this.type = 'ExtrudeGeometry'; + + this.parameters = { + shapes: shapes, + options: options + }; + + this.fromBufferGeometry( new ExtrudeBufferGeometry( shapes, options ) ); + this.mergeVertices(); + + } + + ExtrudeGeometry.prototype = Object.create( Geometry.prototype ); + ExtrudeGeometry.prototype.constructor = ExtrudeGeometry; + + // ExtrudeBufferGeometry + + function ExtrudeBufferGeometry( shapes, options ) { + + if ( typeof ( shapes ) === "undefined" ) { shapes = []; return; } - Geometry.call( this ); + BufferGeometry.call( this ); - this.type = 'ExtrudeGeometry'; + this.type = 'ExtrudeBufferGeometry'; shapes = Array.isArray( shapes ) ? shapes : [ shapes ]; this.addShapeList( shapes, options ); - this.computeFaceNormals(); + this.computeVertexNormals(); // can't really use automatic vertex normals // as then front and back sides get smoothed too @@ -26222,12 +26379,32 @@ } - ExtrudeGeometry.prototype = Object.create( Geometry.prototype ); - ExtrudeGeometry.prototype.constructor = ExtrudeGeometry; + ExtrudeBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); + ExtrudeBufferGeometry.prototype.constructor = ExtrudeBufferGeometry; - ExtrudeGeometry.prototype.addShapeList = function ( shapes, options ) { + ExtrudeBufferGeometry.prototype.getArrays = function () { + + var positionAttribute = this.getAttribute( "position" ); + var verticesArray = positionAttribute ? Array.prototype.slice.call( positionAttribute.array ) : []; + + var uvAttribute = this.getAttribute( "uv" ); + var uvArray = uvAttribute ? Array.prototype.slice.call( uvAttribute.array ) : []; + + var IndexAttribute = this.index; + var indicesArray = IndexAttribute ? Array.prototype.slice.call( IndexAttribute.array ) : []; + + return { + position: verticesArray, + uv: uvArray, + index: indicesArray + }; + + }; + + ExtrudeBufferGeometry.prototype.addShapeList = function ( shapes, options ) { var sl = shapes.length; + options.arrays = this.getArrays(); for ( var s = 0; s < sl; s ++ ) { @@ -26236,9 +26413,21 @@ } + this.setIndex( options.arrays.index ); + this.addAttribute( 'position', new Float32BufferAttribute( options.arrays.position, 3 ) ); + this.addAttribute( 'uv', new Float32BufferAttribute( options.arrays.uv, 2 ) ); + }; - ExtrudeGeometry.prototype.addShape = function ( shape, options ) { + ExtrudeBufferGeometry.prototype.addShape = function ( shape, options ) { + + var arrays = options.arrays ? options.arrays : this.getArrays(); + var verticesArray = arrays.position; + var indicesArray = arrays.index; + var uvArray = arrays.uv; + + var placeholder = []; + var amount = options.amount !== undefined ? options.amount : 100; @@ -26295,8 +26484,6 @@ var ahole, h, hl; // looping of holes var scope = this; - var shapesOffset = this.vertices.length; - var shapePoints = shape.extractPoints( curveSegments ); var vertices = shapePoints.shape; @@ -26367,13 +26554,15 @@ // inPt' is the intersection of the two lines parallel to the two // adjacent edges of inPt at a distance of 1 unit on the left side. - var v_trans_x, v_trans_y, shrink_by = 1; // resulting translation vector for inPt + var v_trans_x, v_trans_y, shrink_by = 1; // resulting translation vector for inPt // good reading for geometry algorithms (here: line-line intersection) // http://geomalgorithms.com/a05-_intersect-1.html - var v_prev_x = inPt.x - inPrev.x, v_prev_y = inPt.y - inPrev.y; - var v_next_x = inNext.x - inPt.x, v_next_y = inNext.y - inPt.y; + var v_prev_x = inPt.x - inPrev.x, + v_prev_y = inPt.y - inPrev.y; + var v_next_x = inNext.x - inPt.x, + v_next_y = inNext.y - inPt.y; var v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y ); @@ -26399,9 +26588,9 @@ // scaling factor for v_prev to intersection point - var sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y - - ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) / - ( v_prev_x * v_next_y - v_prev_y * v_next_x ); + var sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y - + ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) / + ( v_prev_x * v_next_y - v_prev_y * v_next_x ); // vector from inPt to intersection point @@ -26413,7 +26602,7 @@ var v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y ); if ( v_trans_lensq <= 2 ) { - return new Vector2( v_trans_x, v_trans_y ); + return new Vector2( v_trans_x, v_trans_y ); } else { @@ -26425,7 +26614,7 @@ // handle special case of collinear edges - var direction_eq = false; // assumes: opposite + var direction_eq = false; // assumes: opposite if ( v_prev_x > Number.EPSILON ) { if ( v_next_x > Number.EPSILON ) { @@ -26460,7 +26649,7 @@ // console.log("Warning: lines are a straight sequence"); v_trans_x = - v_prev_y; - v_trans_y = v_prev_x; + v_trans_y = v_prev_x; shrink_by = Math.sqrt( v_prev_lensq ); } else { @@ -26474,7 +26663,7 @@ } - return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); + return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); } @@ -26493,7 +26682,8 @@ } - var holesMovements = [], oneHoleMovements, verticesMovements = contourMovements.concat(); + var holesMovements = [], + oneHoleMovements, verticesMovements = contourMovements.concat(); for ( h = 0, hl = holes.length; h < hl; h ++ ) { @@ -26533,7 +26723,7 @@ vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); - v( vert.x, vert.y, - z ); + v( vert.x, vert.y, - z ); } @@ -26548,7 +26738,7 @@ vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); - v( vert.x, vert.y, - z ); + v( vert.x, vert.y, - z ); } @@ -26622,7 +26812,7 @@ for ( b = bevelSegments - 1; b >= 0; b -- ) { t = b / bevelSegments; - z = bevelThickness * Math.cos ( t * Math.PI / 2 ); + z = bevelThickness * Math.cos( t * Math.PI / 2 ); bs = bevelSize * Math.sin( t * Math.PI / 2 ); // contract shape @@ -26630,7 +26820,7 @@ for ( i = 0, il = contour.length; i < il; i ++ ) { vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); - v( vert.x, vert.y, amount + z ); + v( vert.x, vert.y, amount + z ); } @@ -26647,7 +26837,7 @@ if ( ! extrudeByPath ) { - v( vert.x, vert.y, amount + z ); + v( vert.x, vert.y, amount + z ); } else { @@ -26676,6 +26866,8 @@ function buildLidFaces() { + var start = verticesArray.length/3; + if ( bevelEnabled ) { var layer = 0; // steps + 1 @@ -26724,12 +26916,15 @@ } + scope.addGroup( start, verticesArray.length/3 -start, options.material !== undefined ? options.material : 0); + } // Create faces for the z-sides of the shape function buildSideFaces() { + var start = verticesArray.length/3; var layeroffset = 0; sidewalls( contour, layeroffset ); layeroffset += contour.length; @@ -26744,6 +26939,10 @@ } + + scope.addGroup( start, verticesArray.length/3 -start, options.extrudeMaterial !== undefined ? options.extrudeMaterial : 1); + + } function sidewalls( contour, layeroffset ) { @@ -26759,7 +26958,8 @@ //console.log('b', i,j, i-1, k,vertices.length); - var s = 0, sl = steps + bevelSegments * 2; + var s = 0, + sl = steps + bevelSegments * 2; for ( s = 0; s < sl; s ++ ) { @@ -26779,41 +26979,76 @@ } - function v( x, y, z ) { - scope.vertices.push( new Vector3( x, y, z ) ); + placeholder.push( x ); + placeholder.push( y ); + placeholder.push( z ); } + function f3( a, b, c ) { - a += shapesOffset; - b += shapesOffset; - c += shapesOffset; + addVertex( a ); + addVertex( b ); + addVertex( c ); - scope.faces.push( new Face3( a, b, c, null, null, 0 ) ); + var nextIndex = verticesArray.length / 3; + var uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); - var uvs = uvgen.generateTopUV( scope, a, b, c ); - - scope.faceVertexUvs[ 0 ].push( uvs ); + addUV( uvs[ 0 ] ); + addUV( uvs[ 1 ] ); + addUV( uvs[ 2 ] ); } function f4( a, b, c, d, wallContour, stepIndex, stepsLength, contourIndex1, contourIndex2 ) { - a += shapesOffset; - b += shapesOffset; - c += shapesOffset; - d += shapesOffset; + addVertex( a ); + addVertex( b ); + addVertex( d ); - scope.faces.push( new Face3( a, b, d, null, null, 1 ) ); - scope.faces.push( new Face3( b, c, d, null, null, 1 ) ); + addVertex( b ); + addVertex( c ); + addVertex( d ); - var uvs = uvgen.generateSideWallUV( scope, a, b, c, d ); - scope.faceVertexUvs[ 0 ].push( [ uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] ] ); - scope.faceVertexUvs[ 0 ].push( [ uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] ] ); + var nextIndex = verticesArray.length / 3; + var uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); + + addUV( uvs[ 0 ] ); + addUV( uvs[ 1 ] ); + addUV( uvs[ 3 ] ); + + addUV( uvs[ 1 ] ); + addUV( uvs[ 2 ] ); + addUV( uvs[ 3 ] ); + + } + + function addVertex( index ) { + + indicesArray.push( verticesArray.length / 3 ); + verticesArray.push( placeholder[ index * 3 + 0 ] ); + verticesArray.push( placeholder[ index * 3 + 1 ] ); + verticesArray.push( placeholder[ index * 3 + 2 ] ); + + } + + + function addUV( vector2 ) { + + uvArray.push( vector2.x ); + uvArray.push( vector2.y ); + + } + + if ( ! options.arrays ) { + + this.setIndex( indicesArray ); + this.addAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) ); + this.addAttribute( 'uv', new Float32BufferAttribute( options.arrays.uv, 2 ) ); } @@ -26821,47 +27056,54 @@ ExtrudeGeometry.WorldUVGenerator = { - generateTopUV: function ( geometry, indexA, indexB, indexC ) { + generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) { - var vertices = geometry.vertices; - - var a = vertices[ indexA ]; - var b = vertices[ indexB ]; - var c = vertices[ indexC ]; + var a_x = vertices[ indexA * 3 ]; + var a_y = vertices[ indexA * 3 + 1 ]; + var b_x = vertices[ indexB * 3 ]; + var b_y = vertices[ indexB * 3 + 1 ]; + var c_x = vertices[ indexC * 3 ]; + var c_y = vertices[ indexC * 3 + 1 ]; return [ - new Vector2( a.x, a.y ), - new Vector2( b.x, b.y ), - new Vector2( c.x, c.y ) + new Vector2( a_x, a_y ), + new Vector2( b_x, b_y ), + new Vector2( c_x, c_y ) ]; }, - generateSideWallUV: function ( geometry, indexA, indexB, indexC, indexD ) { + generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) { - var vertices = geometry.vertices; + var a_x = vertices[ indexA * 3 ]; + var a_y = vertices[ indexA * 3 + 1 ]; + var a_z = vertices[ indexA * 3 + 2 ]; + var b_x = vertices[ indexB * 3 ]; + var b_y = vertices[ indexB * 3 + 1 ]; + var b_z = vertices[ indexB * 3 + 2 ]; + var c_x = vertices[ indexC * 3 ]; + var c_y = vertices[ indexC * 3 + 1 ]; + var c_z = vertices[ indexC * 3 + 2 ]; + var d_x = vertices[ indexD * 3 ]; + var d_y = vertices[ indexD * 3 + 1 ]; + var d_z = vertices[ indexD * 3 + 2 ]; - var a = vertices[ indexA ]; - var b = vertices[ indexB ]; - var c = vertices[ indexC ]; - var d = vertices[ indexD ]; - - if ( Math.abs( a.y - b.y ) < 0.01 ) { + if ( Math.abs( a_y - b_y ) < 0.01 ) { return [ - new Vector2( a.x, 1 - a.z ), - new Vector2( b.x, 1 - b.z ), - new Vector2( c.x, 1 - c.z ), - new Vector2( d.x, 1 - d.z ) + new Vector2( a_x, 1 - a_z ), + new Vector2( b_x, 1 - b_z ), + new Vector2( c_x, 1 - c_z ), + new Vector2( d_x, 1 - d_z ) ]; } else { return [ - new Vector2( a.y, 1 - a.z ), - new Vector2( b.y, 1 - b.z ), - new Vector2( c.y, 1 - c.z ), - new Vector2( d.y, 1 - d.z ) + new Vector2( a_y, 1 - a_z ), + new Vector2( b_y, 1 - b_z ), + new Vector2( c_y, 1 - c_z ), + new Vector2( d_y, 1 - d_z ) ]; } @@ -26888,7 +27130,30 @@ * } */ - function TextGeometry( text, parameters ) { + // TextGeometry + + function TextGeometry( text, parameters ) { + + Geometry.call( this ); + + this.type = 'TextGeometry'; + + this.parameters = { + text: text, + parameters: parameters + }; + + this.fromBufferGeometry( new TextBufferGeometry( text, parameters ) ); + this.mergeVertices(); + + } + + TextGeometry.prototype = Object.create( Geometry.prototype ); + TextGeometry.prototype.constructor = TextGeometry; + + // TextBufferGeometry + + function TextBufferGeometry( text, parameters ) { parameters = parameters || {}; @@ -26913,19 +27178,23 @@ if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8; if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false; - ExtrudeGeometry.call( this, shapes, parameters ); + ExtrudeBufferGeometry.call( this, shapes, parameters ); - this.type = 'TextGeometry'; + this.type = 'TextBufferGeometry'; } - TextGeometry.prototype = Object.create( ExtrudeGeometry.prototype ); - TextGeometry.prototype.constructor = TextGeometry; + TextBufferGeometry.prototype = Object.create( ExtrudeBufferGeometry.prototype ); + TextBufferGeometry.prototype.constructor = TextBufferGeometry; /** * @author mrdoob / http://mrdoob.com/ + * @author benaadams / https://twitter.com/ben_a_adams + * @author Mugen87 / https://github.com/Mugen87 */ + // SphereGeometry + function SphereGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { Geometry.call( this ); @@ -26943,16 +27212,14 @@ }; this.fromBufferGeometry( new SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) ); + this.mergeVertices(); } SphereGeometry.prototype = Object.create( Geometry.prototype ); SphereGeometry.prototype.constructor = SphereGeometry; - /** - * @author benaadams / https://twitter.com/ben_a_adams - * @author Mugen87 / https://github.com/Mugen87 - */ + // SphereBufferGeometry function SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { @@ -27067,8 +27334,11 @@ /** * @author Kaleb Murphy + * @author Mugen87 / https://github.com/Mugen87 */ + // RingGeometry + function RingGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { Geometry.call( this ); @@ -27085,15 +27355,14 @@ }; this.fromBufferGeometry( new RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) ); + this.mergeVertices(); } RingGeometry.prototype = Object.create( Geometry.prototype ); RingGeometry.prototype.constructor = RingGeometry; - /** - * @author Mugen87 / https://github.com/Mugen87 - */ + // RingBufferGeometry function RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { @@ -27211,14 +27480,10 @@ * @author astrodud / http://astrodud.isgreat.org/ * @author zz85 / https://github.com/zz85 * @author bhouston / http://clara.io + * @author Mugen87 / https://github.com/Mugen87 */ - // points - to create a closed torus, one must use a set of points - // like so: [ a, b, c, d, a ], see first is the same as last. - // segments - the number of circumference segments to create - // phiStart - the starting radian - // phiLength - the radian (0 to 2PI) range of the lathed section - // 2PI is a closed lathe, less than 2PI is a portion. + // LatheGeometry function LatheGeometry( points, segments, phiStart, phiLength ) { @@ -27241,9 +27506,7 @@ LatheGeometry.prototype = Object.create( Geometry.prototype ); LatheGeometry.prototype.constructor = LatheGeometry; - /** - * @author Mugen87 / https://github.com/Mugen87 - */ + // LatheBufferGeometry function LatheBufferGeometry( points, segments, phiStart, phiLength ) { @@ -27393,8 +27656,11 @@ /** * @author jonobr1 / http://jonobr1.com + * @author Mugen87 / https://github.com/Mugen87 */ + // ShapeGeometry + function ShapeGeometry( shapes, curveSegments ) { Geometry.call( this ); @@ -27422,9 +27688,7 @@ ShapeGeometry.prototype = Object.create( Geometry.prototype ); ShapeGeometry.prototype.constructor = ShapeGeometry; - /** - * @author Mugen87 / https://github.com/Mugen87 - */ + // ShapeBufferGeometry function ShapeBufferGeometry( shapes, curveSegments ) { @@ -27583,7 +27847,7 @@ // helper variables var thresholdDot = Math.cos( _Math.DEG2RAD * thresholdAngle ); - var edge = [ 0, 0 ], edges = {}; + var edge = [ 0, 0 ], edges = {}, edge1, edge2; var key, keys = [ 'a', 'b', 'c' ]; // prepare source geometry @@ -27615,11 +27879,12 @@ for ( var j = 0; j < 3; j ++ ) { - edge[ 0 ] = face[ keys[ j ] ]; - edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ]; - edge.sort( sortFunction ); + edge1 = face[ keys[ j ] ]; + edge2 = face[ keys[ ( j + 1 ) % 3 ] ]; + edge[ 0 ] = Math.min( edge1, edge2 ); + edge[ 1 ] = Math.max( edge1, edge2 ); - key = edge.toString(); + key = edge[ 0 ] + ',' + edge[ 1 ]; if ( edges[ key ] === undefined ) { @@ -27659,14 +27924,6 @@ this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - // custom array sort function - - function sortFunction( a, b ) { - - return a - b; - - } - } EdgesGeometry.prototype = Object.create( BufferGeometry.prototype ); @@ -27674,8 +27931,11 @@ /** * @author mrdoob / http://mrdoob.com/ + * @author Mugen87 / https://github.com/Mugen87 */ + // CylinderGeometry + function CylinderGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { Geometry.call( this ); @@ -27701,9 +27961,7 @@ CylinderGeometry.prototype = Object.create( Geometry.prototype ); CylinderGeometry.prototype.constructor = CylinderGeometry; - /** - * @author Mugen87 / https://github.com/Mugen87 - */ + // CylinderBufferGeometry function CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { @@ -27745,7 +28003,6 @@ // helper variables var index = 0; - var indexOffset = 0; var indexArray = []; var halfHeight = height / 2; var groupStart = 0; @@ -27984,6 +28241,8 @@ * @author abelnation / http://github.com/abelnation */ + // ConeGeometry + function ConeGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { CylinderGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); @@ -28005,9 +28264,7 @@ ConeGeometry.prototype = Object.create( CylinderGeometry.prototype ); ConeGeometry.prototype.constructor = ConeGeometry; - /** - * @author: abelnation / http://github.com/abelnation - */ + // ConeBufferGeometry function ConeBufferGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { @@ -28031,9 +28288,13 @@ ConeBufferGeometry.prototype.constructor = ConeBufferGeometry; /** + * @author benaadams / https://twitter.com/ben_a_adams + * @author Mugen87 / https://github.com/Mugen87 * @author hughes */ + // CircleGeometry + function CircleGeometry( radius, segments, thetaStart, thetaLength ) { Geometry.call( this ); @@ -28048,16 +28309,14 @@ }; this.fromBufferGeometry( new CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) ); + this.mergeVertices(); } CircleGeometry.prototype = Object.create( Geometry.prototype ); CircleGeometry.prototype.constructor = CircleGeometry; - /** - * @author benaadams / https://twitter.com/ben_a_adams - * @author Mugen87 / https://github.com/Mugen87 - */ + // CircleBufferGeometry function CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) { @@ -28164,6 +28423,7 @@ TorusGeometry: TorusGeometry, TorusBufferGeometry: TorusBufferGeometry, TextGeometry: TextGeometry, + TextBufferGeometry: TextBufferGeometry, SphereGeometry: SphereGeometry, SphereBufferGeometry: SphereBufferGeometry, RingGeometry: RingGeometry, @@ -28175,6 +28435,7 @@ ShapeGeometry: ShapeGeometry, ShapeBufferGeometry: ShapeBufferGeometry, ExtrudeGeometry: ExtrudeGeometry, + ExtrudeBufferGeometry: ExtrudeBufferGeometry, EdgesGeometry: EdgesGeometry, ConeGeometry: ConeGeometry, ConeBufferGeometry: ConeBufferGeometry, @@ -28188,9 +28449,13 @@ /** * @author mrdoob / http://mrdoob.com/ + * + * parameters = { + * opacity: + * } */ - function ShadowMaterial() { + function ShadowMaterial( parameters ) { ShaderMaterial.call( this, { uniforms: UniformsUtils.merge( [ @@ -28218,6 +28483,8 @@ } } ); + this.setValues( parameters ); + } ShadowMaterial.prototype = Object.create( ShaderMaterial.prototype ); @@ -28242,76 +28509,6 @@ RawShaderMaterial.prototype.isRawShaderMaterial = true; - /** - * @author mrdoob / http://mrdoob.com/ - */ - - function MultiMaterial( materials ) { - - this.uuid = _Math.generateUUID(); - - this.type = 'MultiMaterial'; - - this.materials = Array.isArray( materials ) ? materials : []; - - this.visible = true; - - } - - MultiMaterial.prototype = { - - constructor: MultiMaterial, - - isMultiMaterial: true, - - toJSON: function ( meta ) { - - var output = { - metadata: { - version: 4.2, - type: 'material', - generator: 'MaterialExporter' - }, - uuid: this.uuid, - type: this.type, - materials: [] - }; - - var materials = this.materials; - - for ( var i = 0, l = materials.length; i < l; i ++ ) { - - var material = materials[ i ].toJSON( meta ); - delete material.metadata; - - output.materials.push( material ); - - } - - output.visible = this.visible; - - return output; - - }, - - clone: function () { - - var material = new this.constructor(); - - for ( var i = 0; i < this.materials.length; i ++ ) { - - material.materials.push( this.materials[ i ].clone() ); - - } - - material.visible = this.visible; - - return material; - - } - - }; - /** * @author WestLangley / http://github.com/WestLangley * @@ -29000,7 +29197,6 @@ RawShaderMaterial: RawShaderMaterial, ShaderMaterial: ShaderMaterial, PointsMaterial: PointsMaterial, - MultiMaterial: MultiMaterial, MeshPhysicalMaterial: MeshPhysicalMaterial, MeshStandardMaterial: MeshStandardMaterial, MeshPhongMaterial: MeshPhongMaterial, @@ -29247,6 +29443,7 @@ if ( onError ) onError( error ); + scope.manager.itemEnd( url ); scope.manager.itemError( url ); }, 0 ); @@ -29285,6 +29482,7 @@ if ( onError ) onError( event ); + scope.manager.itemEnd( url ); scope.manager.itemError( url ); } @@ -29305,6 +29503,7 @@ if ( onError ) onError( event ); + scope.manager.itemEnd( url ); scope.manager.itemError( url ); }, false ); @@ -29314,6 +29513,12 @@ if ( request.overrideMimeType ) request.overrideMimeType( this.mimeType !== undefined ? this.mimeType : 'text/plain' ); + for ( var header in this.requestHeader ) { + + request.setRequestHeader( header, this.requestHeader[ header ] ); + + } + request.send( null ); } @@ -29350,6 +29555,13 @@ this.mimeType = value; return this; + }, + + setRequestHeader: function ( value ) { + + this.requestHeader = value; + return this; + } } ); @@ -29638,11 +29850,16 @@ if ( onError ) onError( event ); + scope.manager.itemEnd( url ); scope.manager.itemError( url ); }, false ); - if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; + if ( url.substr( 0, 5 ) !== 'data:' ) { + + if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; + + } scope.manager.itemStart( url ); @@ -29750,18 +29967,17 @@ load: function ( url, onLoad, onProgress, onError ) { - var texture = new Texture(); - var loader = new ImageLoader( this.manager ); loader.setCrossOrigin( this.crossOrigin ); loader.setPath( this.path ); - loader.load( url, function ( image ) { + + var texture = new Texture(); + texture.image = loader.load( url, function () { // JPEGs can't have an alpha channel, so memory can be saved by storing them as RGB. var isJPEG = url.search( /\.(jpg|jpeg)$/ ) > 0 || url.search( /^data\:image\/jpeg/ ) === 0; texture.format = isJPEG ? RGBFormat : RGBAFormat; - texture.image = image; texture.needsUpdate = true; if ( onLoad !== undefined ) { @@ -29960,11 +30176,11 @@ update: function ( light ) { + var camera = this.camera; + var fov = _Math.RAD2DEG * 2 * light.angle; var aspect = this.mapSize.width / this.mapSize.height; - var far = light.distance || 500; - - var camera = this.camera; + var far = light.distance || camera.far; if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) { @@ -30172,6 +30388,61 @@ } ); + /** + * @author abelnation / http://github.com/abelnation + */ + + function RectAreaLight( color, intensity, width, height ) { + + Light.call( this, color, intensity ); + + this.type = 'RectAreaLight'; + + this.position.set( 0, 1, 0 ); + this.updateMatrix(); + + this.width = ( width !== undefined ) ? width : 10; + this.height = ( height !== undefined ) ? height : 10; + + // TODO (abelnation): distance/decay + + // TODO (abelnation): update method for RectAreaLight to update transform to lookat target + + // TODO (abelnation): shadows + + } + + // TODO (abelnation): RectAreaLight update when light shape is changed + RectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), { + + constructor: RectAreaLight, + + isRectAreaLight: true, + + copy: function ( source ) { + + Light.prototype.copy.call( this, source ); + + this.width = source.width; + this.height = source.height; + + return this; + + }, + + toJSON: function ( meta ) { + + var data = Light.prototype.toJSON.call( this, meta ); + + data.object.width = this.width; + data.object.height = this.height; + + return data; + + } + + } ); + /** * @author tschw * @author Ben Houston / http://clara.io/ @@ -30181,11 +30452,13 @@ var AnimationUtils = { // same as Array.prototype.slice, but also works on typed arrays - arraySlice: function( array, from, to ) { + arraySlice: function ( array, from, to ) { if ( AnimationUtils.isTypedArray( array ) ) { - return new array.constructor( array.subarray( from, to ) ); + // in ios9 array.subarray(from, undefined) will return empty array + // but array.subarray(from) or array.subarray(from, len) is correct + return new array.constructor( array.subarray( from, to !== undefined ? to : array.length ) ); } @@ -30194,7 +30467,7 @@ }, // converts an array to a specific type - convertArray: function( array, type, forceClone ) { + convertArray: function ( array, type, forceClone ) { if ( ! array || // let 'undefined' and 'null' pass ! forceClone && array.constructor === type ) return array; @@ -30209,7 +30482,7 @@ }, - isTypedArray: function( object ) { + isTypedArray: function ( object ) { return ArrayBuffer.isView( object ) && ! ( object instanceof DataView ); @@ -30217,7 +30490,7 @@ }, // returns an array by which times and values can be sorted - getKeyframeOrder: function( times ) { + getKeyframeOrder: function ( times ) { function compareTime( i, j ) { @@ -30236,7 +30509,7 @@ }, // uses the array previously returned by 'getKeyframeOrder' to sort data - sortedArray: function( values, stride, order ) { + sortedArray: function ( values, stride, order ) { var nValues = values.length; var result = new values.constructor( nValues ); @@ -30258,7 +30531,7 @@ }, // function for parsing AOS keyframe formats - flattenJSON: function( jsonKeys, times, values, valuePropertyName ) { + flattenJSON: function ( jsonKeys, times, values, valuePropertyName ) { var i = 1, key = jsonKeys[ 0 ]; @@ -30291,6 +30564,7 @@ } while ( key !== undefined ); } else if ( value.toArray !== undefined ) { + // ...assume THREE.Math-ish do { @@ -30309,6 +30583,7 @@ } while ( key !== undefined ); } else { + // otherwise push as-is do { @@ -30354,8 +30629,7 @@ * @author tschw */ - function Interpolant( - parameterPositions, sampleValues, sampleSize, resultBuffer ) { + function Interpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { this.parameterPositions = parameterPositions; this._cachedIndex = 0; @@ -30367,9 +30641,7 @@ } - Interpolant.prototype = { - - constructor: Interpolant, + Object.assign( Interpolant.prototype, { evaluate: function( t ) { @@ -30386,10 +30658,10 @@ var right; linear_scan: { - //- See http://jsperf.com/comparison-to-undefined/3 - //- slower code: - //- - //- if ( t >= t1 || t1 === undefined ) { + //- See http://jsperf.com/comparison-to-undefined/3 + //- slower code: + //- + //- if ( t >= t1 || t1 === undefined ) { forward_scan: if ( ! ( t < t1 ) ) { for ( var giveUpAt = i1 + 2; ;) { @@ -30426,8 +30698,8 @@ } - //- slower code: - //- if ( t < t0 || t0 === undefined ) { + //- slower code: + //- if ( t < t0 || t0 === undefined ) { if ( ! ( t >= t0 ) ) { // looping? @@ -30578,15 +30850,16 @@ } - }; + } ); + //!\ DECLARE ALIAS AFTER assign prototype ! Object.assign( Interpolant.prototype, { - beforeStart_: //( 0, t, t0 ), returns this.resultBuffer - Interpolant.prototype.copySampleValue_, + //( 0, t, t0 ), returns this.resultBuffer + beforeStart_: Interpolant.prototype.copySampleValue_, - afterEnd_: //( N-1, tN-1, t ), returns this.resultBuffer - Interpolant.prototype.copySampleValue_ + //( N-1, tN-1, t ), returns this.resultBuffer + afterEnd_: Interpolant.prototype.copySampleValue_, } ); @@ -30600,8 +30873,7 @@ * @author tschw */ - function CubicInterpolant( - parameterPositions, sampleValues, sampleSize, resultBuffer ) { + function CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); @@ -30613,8 +30885,7 @@ } - CubicInterpolant.prototype = - Object.assign( Object.create( Interpolant.prototype ), { + CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { constructor: CubicInterpolant, @@ -30747,16 +31018,13 @@ * @author tschw */ - function LinearInterpolant( - parameterPositions, sampleValues, sampleSize, resultBuffer ) { + function LinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - Interpolant.call( - this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); } - LinearInterpolant.prototype = - Object.assign( Object.create( Interpolant.prototype ), { + LinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { constructor: LinearInterpolant, @@ -30794,16 +31062,13 @@ * @author tschw */ - function DiscreteInterpolant( - parameterPositions, sampleValues, sampleSize, resultBuffer ) { + function DiscreteInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - Interpolant.call( - this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); } - DiscreteInterpolant.prototype = - Object.assign( Object.create( Interpolant.prototype ), { + DiscreteInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { constructor: DiscreteInterpolant, @@ -31173,9 +31438,9 @@ function KeyframeTrackConstructor( name, times, values, interpolation ) { - if( name === undefined ) throw new Error( "track name is undefined" ); + if ( name === undefined ) throw new Error( "track name is undefined" ); - if( times === undefined || times.length === 0 ) { + if ( times === undefined || times.length === 0 ) { throw new Error( "no keyframes in track named " + name ); @@ -31228,16 +31493,13 @@ * @author tschw */ - function QuaternionLinearInterpolant( - parameterPositions, sampleValues, sampleSize, resultBuffer ) { + function QuaternionLinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - Interpolant.call( - this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); } - QuaternionLinearInterpolant.prototype = - Object.assign( Object.create( Interpolant.prototype ), { + QuaternionLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { constructor: QuaternionLinearInterpolant, @@ -31585,7 +31847,7 @@ this.name = name; this.tracks = tracks; - this.duration = ( duration !== undefined ) ? duration : -1; + this.duration = ( duration !== undefined ) ? duration : - 1; this.uuid = _Math.generateUUID(); @@ -31600,58 +31862,9 @@ } - AnimationClip.prototype = { - - constructor: AnimationClip, - - resetDuration: function() { - - var tracks = this.tracks, - duration = 0; - - for ( var i = 0, n = tracks.length; i !== n; ++ i ) { - - var track = this.tracks[ i ]; - - duration = Math.max( duration, track.times[ track.times.length - 1 ] ); - - } - - this.duration = duration; - - }, - - trim: function() { - - for ( var i = 0; i < this.tracks.length; i ++ ) { - - this.tracks[ i ].trim( 0, this.duration ); - - } - - return this; - - }, - - optimize: function() { - - for ( var i = 0; i < this.tracks.length; i ++ ) { - - this.tracks[ i ].optimize(); - - } - - return this; - - } - - }; - - // Static methods: - Object.assign( AnimationClip, { - parse: function( json ) { + parse: function ( json ) { var tracks = [], jsonTracks = json.tracks, @@ -31667,8 +31880,7 @@ }, - - toJSON: function( clip ) { + toJSON: function ( clip ) { var tracks = [], clipTracks = clip.tracks; @@ -31691,8 +31903,7 @@ }, - - CreateFromMorphTargetSequence: function( name, morphTargetSequence, fps, noLoop ) { + CreateFromMorphTargetSequence: function ( name, morphTargetSequence, fps, noLoop ) { var numMorphTargets = morphTargetSequence.length; var tracks = []; @@ -31727,13 +31938,14 @@ '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']', times, values ).scale( 1.0 / fps ) ); + } - return new AnimationClip( name, -1, tracks ); + return new AnimationClip( name, - 1, tracks ); }, - findByName: function( objectOrClipArray, name ) { + findByName: function ( objectOrClipArray, name ) { var clipArray = objectOrClipArray; @@ -31751,13 +31963,14 @@ return clipArray[ i ]; } + } return null; }, - CreateClipsFromMorphTargetSequences: function( morphTargets, fps, noLoop ) { + CreateClipsFromMorphTargetSequences: function ( morphTargets, fps, noLoop ) { var animationToMorphTargets = {}; @@ -31802,7 +32015,7 @@ }, // parse the animation.hierarchy format - parseAnimation: function( animation, bones ) { + parseAnimation: function ( animation, bones ) { if ( ! animation ) { @@ -31811,8 +32024,7 @@ } - var addNonemptyTrack = function( - trackType, trackName, animationKeys, propertyName, destTracks ) { + var addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) { // only return track if there are actually keys. if ( animationKeys.length !== 0 ) { @@ -31820,8 +32032,7 @@ var times = []; var values = []; - AnimationUtils.flattenJSON( - animationKeys, times, values, propertyName ); + AnimationUtils.flattenJSON( animationKeys, times, values, propertyName ); // empty keys are filtered out, so check again if ( times.length !== 0 ) { @@ -31838,7 +32049,7 @@ var clipName = animation.name || 'default'; // automatic length determination in AnimationClip. - var duration = animation.length || -1; + var duration = animation.length || - 1; var fps = animation.fps || 30; var hierarchyTracks = animation.hierarchy || []; @@ -31852,17 +32063,19 @@ // process morph targets in a way exactly compatible // with AnimationHandler.init( animation ) - if ( animationKeys[0].morphTargets ) { + if ( animationKeys[ 0 ].morphTargets ) { // figure out all morph targets used in this track var morphTargetNames = {}; + for ( var k = 0; k < animationKeys.length; k ++ ) { - if ( animationKeys[k].morphTargets ) { + if ( animationKeys[ k ].morphTargets ) { - for ( var m = 0; m < animationKeys[k].morphTargets.length; m ++ ) { + for ( var m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) { + + morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1; - morphTargetNames[ animationKeys[k].morphTargets[m] ] = -1; } } @@ -31877,22 +32090,23 @@ var times = []; var values = []; - for ( var m = 0; m !== animationKeys[k].morphTargets.length; ++ m ) { + for ( var m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) { - var animationKey = animationKeys[k]; + var animationKey = animationKeys[ k ]; times.push( animationKey.time ); values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 ); } - tracks.push( new NumberKeyframeTrack('.morphTargetInfluence[' + morphTargetName + ']', times, values ) ); + tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) ); } duration = morphTargetNames.length * ( fps || 1.0 ); } else { + // ...assume skeletal animation var boneName = '.bones[' + bones[ h ].name + ']'; @@ -31927,6 +32141,50 @@ } ); + Object.assign( AnimationClip.prototype, { + + resetDuration: function () { + + var tracks = this.tracks, duration = 0; + + for ( var i = 0, n = tracks.length; i !== n; ++ i ) { + + var track = this.tracks[ i ]; + + duration = Math.max( duration, track.times[ track.times.length - 1 ] ); + + } + + this.duration = duration; + + }, + + trim: function () { + + for ( var i = 0; i < this.tracks.length; i ++ ) { + + this.tracks[ i ].trim( 0, this.duration ); + + } + + return this; + + }, + + optimize: function () { + + for ( var i = 0; i < this.tracks.length; i ++ ) { + + this.tracks[ i ].optimize(); + + } + + return this; + + } + + } ); + /** * @author mrdoob / http://mrdoob.com/ */ @@ -31945,9 +32203,10 @@ var scope = this; var loader = new FileLoader( scope.manager ); - loader.load( url, function ( text ) { + loader.setResponseType( 'json' ); + loader.load( url, function ( json ) { - onLoad( scope.parse( JSON.parse( text ) ) ); + onLoad( scope.parse( json ) ); }, onProgress, onError ); @@ -32068,18 +32327,6 @@ if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap ); - // MultiMaterial - - if ( json.materials !== undefined ) { - - for ( var i = 0, l = json.materials.length; i < l; i ++ ) { - - material.materials.push( this.parse( json.materials[ i ] ) ); - - } - - } - return material; } @@ -32103,9 +32350,10 @@ var scope = this; var loader = new FileLoader( scope.manager ); - loader.load( url, function ( text ) { + loader.setResponseType( 'json' ); + loader.load( url, function ( json ) { - onLoad( scope.parse( JSON.parse( text ) ) ); + onLoad( scope.parse( json ) ); }, onProgress, onError ); @@ -32117,18 +32365,6 @@ var index = json.data.index; - var TYPED_ARRAYS = { - 'Int8Array': Int8Array, - 'Uint8Array': Uint8Array, - 'Uint8ClampedArray': Uint8ClampedArray, - 'Int16Array': Int16Array, - 'Uint16Array': Uint16Array, - 'Int32Array': Int32Array, - 'Uint32Array': Uint32Array, - 'Float32Array': Float32Array, - 'Float64Array': Float64Array - }; - if ( index !== undefined ) { var typedArray = new TYPED_ARRAYS[ index.type ]( index.array ); @@ -32183,6 +32419,18 @@ } ); + var TYPED_ARRAYS = { + Int8Array: Int8Array, + Uint8Array: Uint8Array, + Uint8ClampedArray: Uint8ClampedArray, + Int16Array: Int16Array, + Uint16Array: Uint16Array, + Int32Array: Int32Array, + Uint32Array: Uint32Array, + Float32Array: Float32Array, + Float64Array: Float64Array + }; + /** * @author alteredq / http://alteredqualia.com/ */ @@ -32195,9 +32443,40 @@ } - Loader.prototype = { + Loader.Handlers = { - constructor: Loader, + handlers: [], + + add: function ( regex, loader ) { + + this.handlers.push( regex, loader ); + + }, + + get: function ( file ) { + + var handlers = this.handlers; + + for ( var i = 0, l = handlers.length; i < l; i += 2 ) { + + var regex = handlers[ i ]; + var loader = handlers[ i + 1 ]; + + if ( regex.test( file ) ) { + + return loader; + + } + + } + + return null; + + } + + }; + + Object.assign( Loader.prototype, { crossOrigin: undefined, @@ -32238,14 +32517,12 @@ CustomBlending: CustomBlending }; - var color, textureLoader, materialLoader; + var color = new Color(); + var textureLoader = new TextureLoader(); + var materialLoader = new MaterialLoader(); return function createMaterial( m, texturePath, crossOrigin ) { - if ( color === undefined ) color = new Color(); - if ( textureLoader === undefined ) textureLoader = new TextureLoader(); - if ( materialLoader === undefined ) materialLoader = new MaterialLoader(); - // convert from old material format var textures = {}; @@ -32483,40 +32760,7 @@ } )() - }; - - Loader.Handlers = { - - handlers: [], - - add: function ( regex, loader ) { - - this.handlers.push( regex, loader ); - - }, - - get: function ( file ) { - - var handlers = this.handlers; - - for ( var i = 0, l = handlers.length; i < l; i += 2 ) { - - var regex = handlers[ i ]; - var loader = handlers[ i + 1 ]; - - if ( regex.test( file ) ) { - - return loader; - - } - - } - - return null; - - } - - }; + } ); /** * @author mrdoob / http://mrdoob.com/ @@ -32540,17 +32784,17 @@ Object.assign( JSONLoader.prototype, { - load: function( url, onLoad, onProgress, onError ) { + load: function ( url, onLoad, onProgress, onError ) { var scope = this; var texturePath = this.texturePath && ( typeof this.texturePath === "string" ) ? this.texturePath : Loader.prototype.extractUrlBase( url ); var loader = new FileLoader( this.manager ); + loader.setResponseType( 'json' ); loader.setWithCredentials( this.withCredentials ); - loader.load( url, function ( text ) { + loader.load( url, function ( json ) { - var json = JSON.parse( text ); var metadata = json.metadata; if ( metadata !== undefined ) { @@ -32590,21 +32834,9 @@ }, - parse: function ( json, texturePath ) { + parse: ( function () { - var geometry = new Geometry(), - scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0; - - parseModel( scale ); - - parseSkin(); - parseMorphing( scale ); - parseAnimations(); - - geometry.computeFaceNormals(); - geometry.computeBoundingSphere(); - - function parseModel( scale ) { + function parseModel( json, geometry ) { function isBitSet( value, position ) { @@ -32614,27 +32846,30 @@ var i, j, fi, - offset, zLength, + offset, zLength, - colorIndex, normalIndex, uvIndex, materialIndex, + colorIndex, normalIndex, uvIndex, materialIndex, - type, - isQuad, - hasMaterial, - hasFaceVertexUv, - hasFaceNormal, hasFaceVertexNormal, - hasFaceColor, hasFaceVertexColor, + type, + isQuad, + hasMaterial, + hasFaceVertexUv, + hasFaceNormal, hasFaceVertexNormal, + hasFaceColor, hasFaceVertexColor, - vertex, face, faceA, faceB, hex, normal, + vertex, face, faceA, faceB, hex, normal, - uvLayer, uv, u, v, + uvLayer, uv, u, v, - faces = json.faces, - vertices = json.vertices, - normals = json.normals, - colors = json.colors, + faces = json.faces, + vertices = json.vertices, + normals = json.normals, + colors = json.colors, + + scale = json.scale, + + nUvLayers = 0; - nUvLayers = 0; if ( json.uvs !== undefined ) { @@ -32676,14 +32911,13 @@ type = faces[ offset ++ ]; - - isQuad = isBitSet( type, 0 ); - hasMaterial = isBitSet( type, 1 ); - hasFaceVertexUv = isBitSet( type, 3 ); - hasFaceNormal = isBitSet( type, 4 ); + isQuad = isBitSet( type, 0 ); + hasMaterial = isBitSet( type, 1 ); + hasFaceVertexUv = isBitSet( type, 3 ); + hasFaceNormal = isBitSet( type, 4 ); hasFaceVertexNormal = isBitSet( type, 5 ); - hasFaceColor = isBitSet( type, 6 ); - hasFaceVertexColor = isBitSet( type, 7 ); + hasFaceColor = isBitSet( type, 6 ); + hasFaceVertexColor = isBitSet( type, 7 ); // console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor); @@ -32904,7 +33138,7 @@ } - function parseSkin() { + function parseSkin( json, geometry ) { var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2; @@ -32912,7 +33146,7 @@ for ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) { - var x = json.skinWeights[ i ]; + var x = json.skinWeights[ i ]; var y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0; var z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0; var w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0; @@ -32927,7 +33161,7 @@ for ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) { - var a = json.skinIndices[ i ]; + var a = json.skinIndices[ i ]; var b = ( influencesPerVertex > 1 ) ? json.skinIndices[ i + 1 ] : 0; var c = ( influencesPerVertex > 2 ) ? json.skinIndices[ i + 2 ] : 0; var d = ( influencesPerVertex > 3 ) ? json.skinIndices[ i + 3 ] : 0; @@ -32949,7 +33183,9 @@ } - function parseMorphing( scale ) { + function parseMorphing( json, geometry ) { + + var scale = json.scale; if ( json.morphTargets !== undefined ) { @@ -32994,7 +33230,7 @@ } - function parseAnimations() { + function parseAnimations( json, geometry ) { var outputAnimations = []; @@ -33041,19 +33277,50 @@ } - if ( json.materials === undefined || json.materials.length === 0 ) { + return function ( json, texturePath ) { - return { geometry: geometry }; + if ( json.data !== undefined ) { - } else { + // Geometry 4.0 spec + json = json.data; - var materials = Loader.prototype.initMaterials( json.materials, texturePath, this.crossOrigin ); + } - return { geometry: geometry, materials: materials }; + if ( json.scale !== undefined ) { - } + json.scale = 1.0 / json.scale; - } + } else { + + json.scale = 1.0; + + } + + var geometry = new Geometry(); + + parseModel( json, geometry ); + parseSkin( json, geometry ); + parseMorphing( json, geometry ); + parseAnimations( json, geometry ); + + geometry.computeFaceNormals(); + geometry.computeBoundingSphere(); + + if ( json.materials === undefined || json.materials.length === 0 ) { + + return { geometry: geometry }; + + } else { + + var materials = Loader.prototype.initMaterials( json.materials, texturePath, this.crossOrigin ); + + return { geometry: geometry, materials: materials }; + + } + + }; + + } )() } ); @@ -33331,7 +33598,7 @@ case 'Geometry': - geometry = geometryLoader.parse( data.data, this.texturePath ).geometry; + geometry = geometryLoader.parse( data, this.texturePath ).geometry; break; @@ -33368,8 +33635,27 @@ for ( var i = 0, l = json.length; i < l; i ++ ) { - var material = loader.parse( json[ i ] ); - materials[ material.uuid ] = material; + var data = json[ i ]; + + if ( data.type === 'MultiMaterial' ) { + + // Deprecated + + var array = []; + + for ( var j = 0; j < data.materials.length; j ++ ) { + + array.push( loader.parse( data.materials[ j ] ) ); + + } + + materials[ data.uuid ] = array; + + } else { + + materials[ data.uuid ] = loader.parse( data ); + + } } @@ -33410,6 +33696,7 @@ }, undefined, function () { + scope.manager.itemEnd( url ); scope.manager.itemError( url ); } ); @@ -33440,32 +33727,6 @@ parseTextures: function ( json, images ) { - var TextureMapping = { - UVMapping: UVMapping, - CubeReflectionMapping: CubeReflectionMapping, - CubeRefractionMapping: CubeRefractionMapping, - EquirectangularReflectionMapping: EquirectangularReflectionMapping, - EquirectangularRefractionMapping: EquirectangularRefractionMapping, - SphericalReflectionMapping: SphericalReflectionMapping, - CubeUVReflectionMapping: CubeUVReflectionMapping, - CubeUVRefractionMapping: CubeUVRefractionMapping - }; - - var TextureWrapping = { - RepeatWrapping: RepeatWrapping, - ClampToEdgeWrapping: ClampToEdgeWrapping, - MirroredRepeatWrapping: MirroredRepeatWrapping - }; - - var TextureFilter = { - NearestFilter: NearestFilter, - NearestMipMapNearestFilter: NearestMipMapNearestFilter, - NearestMipMapLinearFilter: NearestMipMapLinearFilter, - LinearFilter: LinearFilter, - LinearMipMapNearestFilter: LinearMipMapNearestFilter, - LinearMipMapLinearFilter: LinearMipMapLinearFilter - }; - function parseConstant( value, type ) { if ( typeof( value ) === 'number' ) return value; @@ -33503,19 +33764,19 @@ if ( data.name !== undefined ) texture.name = data.name; - if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TextureMapping ); + if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING ); if ( data.offset !== undefined ) texture.offset.fromArray( data.offset ); if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat ); if ( data.wrap !== undefined ) { - texture.wrapS = parseConstant( data.wrap[ 0 ], TextureWrapping ); - texture.wrapT = parseConstant( data.wrap[ 1 ], TextureWrapping ); + texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING ); + texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING ); } - if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TextureFilter ); - if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TextureFilter ); + if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER ); + if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER ); if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy; if ( data.flipY !== undefined ) texture.flipY = data.flipY; @@ -33554,6 +33815,28 @@ if ( name === undefined ) return undefined; + if ( Array.isArray( name ) ) { + + var array = []; + + for ( var i = 0, l = name.length; i < l; i ++ ) { + + var uuid = name[ i ]; + + if ( materials[ uuid ] === undefined ) { + + console.warn( 'THREE.ObjectLoader: Undefined material', uuid ); + + } + + array.push( materials[ uuid ] ); + + } + + return array; + + } + if ( materials[ name ] === undefined ) { console.warn( 'THREE.ObjectLoader: Undefined material', name ); @@ -33632,6 +33915,12 @@ break; + case 'RectAreaLight': + + object = new RectAreaLight( data.color, data.intensity, data.width, data.height ); + + break; + case 'SpotLight': object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay ); @@ -33644,6 +33933,10 @@ break; + case 'SkinnedMesh': + + console.warn( 'THREE.ObjectLoader.parseObject() does not support SkinnedMesh yet.' ); + case 'Mesh': var geometry = getGeometry( data.geometry ); @@ -33673,6 +33966,12 @@ break; + case 'LineLoop': + + object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) ); + + break; + case 'LineSegments': object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) ); @@ -33698,10 +33997,6 @@ break; - case 'SkinnedMesh': - - console.warn( 'THREE.ObjectLoader.parseObject() does not support SkinnedMesh type. Instantiates Object3D instead.' ); - default: object = new Object3D(); @@ -33777,6 +34072,32 @@ } ); + var TEXTURE_MAPPING = { + UVMapping: UVMapping, + CubeReflectionMapping: CubeReflectionMapping, + CubeRefractionMapping: CubeRefractionMapping, + EquirectangularReflectionMapping: EquirectangularReflectionMapping, + EquirectangularRefractionMapping: EquirectangularRefractionMapping, + SphericalReflectionMapping: SphericalReflectionMapping, + CubeUVReflectionMapping: CubeUVReflectionMapping, + CubeUVRefractionMapping: CubeUVRefractionMapping + }; + + var TEXTURE_WRAPPING = { + RepeatWrapping: RepeatWrapping, + ClampToEdgeWrapping: ClampToEdgeWrapping, + MirroredRepeatWrapping: MirroredRepeatWrapping + }; + + var TEXTURE_FILTER = { + NearestFilter: NearestFilter, + NearestMipMapNearestFilter: NearestMipMapNearestFilter, + NearestMipMapLinearFilter: NearestMipMapLinearFilter, + LinearFilter: LinearFilter, + LinearMipMapNearestFilter: LinearMipMapNearestFilter, + LinearMipMapLinearFilter: LinearMipMapLinearFilter + }; + /** * @author zz85 / http://www.lab4games.net/zz85/blog * @@ -33861,30 +34182,30 @@ * @author zz85 / http://www.lab4games.net/zz85/blog * Extensible curve object * - * Some common of Curve methods + * Some common of curve methods: * .getPoint(t), getTangent(t) * .getPointAt(u), getTangentAt(u) * .getPoints(), .getSpacedPoints() * .getLength() * .updateArcLengths() * - * This following classes subclasses THREE.Curve: + * This following curves inherit from THREE.Curve: * - * -- 2d classes -- + * -- 2D curves -- + * THREE.ArcCurve + * THREE.CubicBezierCurve + * THREE.EllipseCurve * THREE.LineCurve * THREE.QuadraticBezierCurve - * THREE.CubicBezierCurve * THREE.SplineCurve - * THREE.ArcCurve - * THREE.EllipseCurve * - * -- 3d classes -- + * -- 3D curves -- + * THREE.CatmullRomCurve3 + * THREE.CubicBezierCurve3 * THREE.LineCurve3 * THREE.QuadraticBezierCurve3 - * THREE.CubicBezierCurve3 - * THREE.CatmullRomCurve3 * - * A series of curves can be represented as a THREE.CurvePath + * A series of curves can be represented as a THREE.CurvePath. * **/ @@ -33892,18 +34213,20 @@ * Abstract Curve base class **************************************************************/ - function Curve() {} + function Curve() { - Curve.prototype = { + this.arcLengthDivisions = 200; - constructor: Curve, + } + + Object.assign( Curve.prototype, { // Virtual base class method to overwrite and implement in subclasses // - t [0 .. 1] - getPoint: function ( t ) { + getPoint: function () { - console.warn( "THREE.Curve: Warning, getPoint() not implemented!" ); + console.warn( 'THREE.Curve: .getPoint() not implemented.' ); return null; }, @@ -33922,7 +34245,7 @@ getPoints: function ( divisions ) { - if ( isNaN( divisions ) ) divisions = 5; + if ( divisions === undefined ) divisions = 5; var points = []; @@ -33940,7 +34263,7 @@ getSpacedPoints: function ( divisions ) { - if ( isNaN( divisions ) ) divisions = 5; + if ( divisions === undefined ) divisions = 5; var points = []; @@ -33967,13 +34290,12 @@ getLengths: function ( divisions ) { - if ( isNaN( divisions ) ) divisions = ( this.__arcLengthDivisions ) ? ( this.__arcLengthDivisions ) : 200; + if ( divisions === undefined ) divisions = this.arcLengthDivisions; - if ( this.cacheArcLengths - && ( this.cacheArcLengths.length === divisions + 1 ) - && ! this.needsUpdate ) { + if ( this.cacheArcLengths && + ( this.cacheArcLengths.length === divisions + 1 ) && + ! this.needsUpdate ) { - //console.log( "cached", this.cacheArcLengths ); return this.cacheArcLengths; } @@ -33988,7 +34310,7 @@ for ( p = 1; p <= divisions; p ++ ) { - current = this.getPoint ( p / divisions ); + current = this.getPoint( p / divisions ); sum += current.distanceTo( last ); cache.push( sum ); last = current; @@ -33997,11 +34319,11 @@ this.cacheArcLengths = cache; - return cache; // { sums: cache, sum:sum }; Sum is in the last element. + return cache; // { sums: cache, sum: sum }; Sum is in the last element. }, - updateArcLengths: function() { + updateArcLengths: function () { this.needsUpdate = true; this.getLengths(); @@ -34028,8 +34350,6 @@ } - //var time = Date.now(); - // binary search for the index with largest value smaller than target u distance var low = 0, high = il - 1, comparison; @@ -34061,12 +34381,9 @@ i = high; - //console.log('b' , i, low, high, Date.now()- time); - if ( arcLengths[ i ] === targetArcLength ) { - var t = i / ( il - 1 ); - return t; + return i / ( il - 1 ); } @@ -34094,7 +34411,7 @@ // 2 points a small delta apart will be used to find its gradient // which seems to give a reasonable approximation - getTangent: function( t ) { + getTangent: function ( t ) { var delta = 0.0001; var t1 = t - delta; @@ -34237,10 +34554,12 @@ } - }; + } ); function LineCurve( v1, v2 ) { + Curve.call( this ); + this.v1 = v1; this.v2 = v2; @@ -34294,6 +34613,8 @@ function CurvePath() { + Curve.call( this ); + this.curves = []; this.autoClose = false; // Automatically closes the path @@ -34381,7 +34702,7 @@ this.needsUpdate = true; this.cacheLengths = null; - this.getLengths(); + this.getCurveLengths(); }, @@ -34418,7 +34739,7 @@ getSpacedPoints: function ( divisions ) { - if ( isNaN( divisions ) ) divisions = 40; + if ( divisions === undefined ) divisions = 40; var points = []; @@ -34518,6 +34839,8 @@ function EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { + Curve.call( this ); + this.aX = aX; this.aY = aY; @@ -34600,6 +34923,8 @@ function SplineCurve( points /* array of Vector2 */ ) { + Curve.call( this ); + this.points = ( points === undefined ) ? [] : points; } @@ -34631,6 +34956,8 @@ function CubicBezierCurve( v0, v1, v2, v3 ) { + Curve.call( this ); + this.v0 = v0; this.v1 = v1; this.v2 = v2; @@ -34654,6 +34981,8 @@ function QuadraticBezierCurve( v0, v1, v2 ) { + Curve.call( this ); + this.v0 = v0; this.v1 = v1; this.v2 = v2; @@ -34885,7 +35214,7 @@ } - ShapePath.prototype = { + Object.assign( ShapePath.prototype, { moveTo: function ( x, y ) { @@ -35146,7 +35475,7 @@ } - }; + } ); /** * @author zz85 / http://www.lab4games.net/zz85/blog @@ -35431,53 +35760,6 @@ } ); - /** - * @author abelnation / http://github.com/abelnation - */ - - function RectAreaLight ( color, intensity, width, height ) { - - Light.call( this, color, intensity ); - - this.type = 'RectAreaLight'; - - this.position.set( 0, 1, 0 ); - this.updateMatrix(); - - this.width = ( width !== undefined ) ? width : 10; - this.height = ( height !== undefined ) ? height : 10; - - // TODO (abelnation): distance/decay - - // TODO (abelnation): update method for RectAreaLight to update transform to lookat target - - // TODO (abelnation): shadows - // this.shadow = new THREE.RectAreaLightShadow( new THREE.PerspectiveCamera( 90, 1, 0.5, 500 ) ); - - } - - // TODO (abelnation): RectAreaLight update when light shape is changed - RectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), { - - constructor: RectAreaLight, - - isRectAreaLight: true, - - copy: function ( source ) { - - Light.prototype.copy.call( this, source ); - - this.width = source.width; - this.height = source.height; - - // this.shadow = source.shadow.clone(); - - return this; - - } - - } ); - /** * @author mrdoob / http://mrdoob.com/ */ @@ -35504,7 +35786,7 @@ update: ( function () { - var instance, focus, fov, aspect, near, far, zoom; + var instance, focus, fov, aspect, near, far, zoom, eyeSep; var eyeRight = new Matrix4(); var eyeLeft = new Matrix4(); @@ -35513,7 +35795,7 @@ var needsUpdate = instance !== this || focus !== camera.focus || fov !== camera.fov || aspect !== camera.aspect * this.aspect || near !== camera.near || - far !== camera.far || zoom !== camera.zoom; + far !== camera.far || zoom !== camera.zoom || eyeSep !== this.eyeSep; if ( needsUpdate ) { @@ -35529,7 +35811,7 @@ // http://paulbourke.net/stereographics/stereorender/ var projectionMatrix = camera.projectionMatrix.clone(); - var eyeSep = this.eyeSep / 2; + eyeSep = this.eyeSep / 2; var eyeSepOnProjection = eyeSep * near / focus; var ymax = ( near * Math.tan( _Math.DEG2RAD * fov * 0.5 ) ) / zoom; var xmin, xmax; @@ -35618,6 +35900,7 @@ var options = { format: RGBFormat, magFilter: LinearFilter, minFilter: LinearFilter }; this.renderTarget = new WebGLRenderTargetCube( cubeResolution, cubeResolution, options ); + this.renderTarget.texture.name = "CubeCamera"; this.updateCubeMap = function ( renderer, scene ) { @@ -35657,6 +35940,27 @@ CubeCamera.prototype = Object.create( Object3D.prototype ); CubeCamera.prototype.constructor = CubeCamera; + /** + * @author mrdoob / http://mrdoob.com/ + */ + + function ArrayCamera( array ) { + + PerspectiveCamera.call( this ); + + this.enabled = false; + this.cameras = array || []; + + } + + ArrayCamera.prototype = Object.assign( Object.create( PerspectiveCamera.prototype ), { + + constructor: ArrayCamera, + + isArrayCamera: true + + } ); + /** * @author mrdoob / http://mrdoob.com/ */ @@ -36066,8 +36370,7 @@ return this.gain.gain.value; }, - - + setVolume: function ( value ) { this.gain.gain.value = value; @@ -36265,12 +36568,10 @@ } - PropertyMixer.prototype = { - - constructor: PropertyMixer, + Object.assign( PropertyMixer.prototype, { // accumulate data in the 'incoming' region into 'accu' - accumulate: function( accuIndex, weight ) { + accumulate: function ( accuIndex, weight ) { // note: happily accumulating nothing when weight = 0, the caller knows // the weight and shouldn't have made the call in the first place @@ -36308,7 +36609,7 @@ }, // apply the state of 'accu' to the binding when accus differ - apply: function( accuIndex ) { + apply: function ( accuIndex ) { var stride = this.valueSize, buffer = this.buffer, @@ -36327,7 +36628,7 @@ var originalValueOffset = stride * 3; this._mixBufferRegion( - buffer, offset, originalValueOffset, 1 - weight, stride ); + buffer, offset, originalValueOffset, 1 - weight, stride ); } @@ -36347,7 +36648,7 @@ }, // remember the state of the bound property and copy it to both accus - saveOriginalState: function() { + saveOriginalState: function () { var binding = this.binding; @@ -36370,7 +36671,7 @@ }, // apply the state previously taken via 'saveOriginalState' to the binding - restoreOriginalState: function() { + restoreOriginalState: function () { var originalValueOffset = this.valueSize * 3; this.binding.setValue( this.buffer, originalValueOffset ); @@ -36380,7 +36681,7 @@ // mix functions - _select: function( buffer, dstOffset, srcOffset, t, stride ) { + _select: function ( buffer, dstOffset, srcOffset, t, stride ) { if ( t >= 0.5 ) { @@ -36394,14 +36695,13 @@ }, - _slerp: function( buffer, dstOffset, srcOffset, t, stride ) { + _slerp: function ( buffer, dstOffset, srcOffset, t ) { - Quaternion.slerpFlat( buffer, dstOffset, - buffer, dstOffset, buffer, srcOffset, t ); + Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t ); }, - _lerp: function( buffer, dstOffset, srcOffset, t, stride ) { + _lerp: function ( buffer, dstOffset, srcOffset, t, stride ) { var s = 1 - t; @@ -36415,7 +36715,7 @@ } - }; + } ); /** * @@ -36427,275 +36727,263 @@ * @author tschw */ + function Composite( targetGroup, path, optionalParsedPath ) { + + var parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path ); + + this._targetGroup = targetGroup; + this._bindings = targetGroup.subscribe_( path, parsedPath ); + + } + + Object.assign( Composite.prototype, { + + getValue: function ( array, offset ) { + + this.bind(); // bind all binding + + var firstValidIndex = this._targetGroup.nCachedObjects_, + binding = this._bindings[ firstValidIndex ]; + + // and only call .getValue on the first + if ( binding !== undefined ) binding.getValue( array, offset ); + + }, + + setValue: function ( array, offset ) { + + var bindings = this._bindings; + + for ( var i = this._targetGroup.nCachedObjects_, + n = bindings.length; i !== n; ++ i ) { + + bindings[ i ].setValue( array, offset ); + + } + + }, + + bind: function () { + + var bindings = this._bindings; + + for ( var i = this._targetGroup.nCachedObjects_, + n = bindings.length; i !== n; ++ i ) { + + bindings[ i ].bind(); + + } + + }, + + unbind: function () { + + var bindings = this._bindings; + + for ( var i = this._targetGroup.nCachedObjects_, + n = bindings.length; i !== n; ++ i ) { + + bindings[ i ].unbind(); + + } + + } + + } ); + + function PropertyBinding( rootNode, path, parsedPath ) { this.path = path; - this.parsedPath = parsedPath || - PropertyBinding.parseTrackName( path ); + this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path ); - this.node = PropertyBinding.findNode( - rootNode, this.parsedPath.nodeName ) || rootNode; + this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ) || rootNode; this.rootNode = rootNode; } - PropertyBinding.prototype = { + Object.assign( PropertyBinding, { - constructor: PropertyBinding, + Composite: Composite, - getValue: function getValue_unbound( targetArray, offset ) { + create: function ( root, path, parsedPath ) { - this.bind(); - this.getValue( targetArray, offset ); + if ( ! ( root && root.isAnimationObjectGroup ) ) { - // Note: This class uses a State pattern on a per-method basis: - // 'bind' sets 'this.getValue' / 'setValue' and shadows the - // prototype version of these methods with one that represents - // the bound state. When the property is not found, the methods - // become no-ops. - - }, - - setValue: function getValue_unbound( sourceArray, offset ) { - - this.bind(); - this.setValue( sourceArray, offset ); - - }, - - // create getter / setter pair for a property in the scene graph - bind: function() { - - var targetObject = this.node, - parsedPath = this.parsedPath, - - objectName = parsedPath.objectName, - propertyName = parsedPath.propertyName, - propertyIndex = parsedPath.propertyIndex; - - if ( ! targetObject ) { - - targetObject = PropertyBinding.findNode( - this.rootNode, parsedPath.nodeName ) || this.rootNode; - - this.node = targetObject; - - } - - // set fail state so we can just 'return' on error - this.getValue = this._getValue_unavailable; - this.setValue = this._setValue_unavailable; - - // ensure there is a value node - if ( ! targetObject ) { - - console.error( " trying to update node for track: " + this.path + " but it wasn't found." ); - return; - - } - - if ( objectName ) { - - var objectIndex = parsedPath.objectIndex; - - // special cases were we need to reach deeper into the hierarchy to get the face materials.... - switch ( objectName ) { - - case 'materials': - - if ( ! targetObject.material ) { - - console.error( ' can not bind to material as node does not have a material', this ); - return; - - } - - if ( ! targetObject.material.materials ) { - - console.error( ' can not bind to material.materials as node.material does not have a materials array', this ); - return; - - } - - targetObject = targetObject.material.materials; - - break; - - case 'bones': - - if ( ! targetObject.skeleton ) { - - console.error( ' can not bind to bones as node does not have a skeleton', this ); - return; - - } - - // potential future optimization: skip this if propertyIndex is already an integer - // and convert the integer string to a true integer. - - targetObject = targetObject.skeleton.bones; - - // support resolving morphTarget names into indices. - for ( var i = 0; i < targetObject.length; i ++ ) { - - if ( targetObject[ i ].name === objectIndex ) { - - objectIndex = i; - break; - - } - - } - - break; - - default: - - if ( targetObject[ objectName ] === undefined ) { - - console.error( ' can not bind to objectName of node, undefined', this ); - return; - - } - - targetObject = targetObject[ objectName ]; - - } - - - if ( objectIndex !== undefined ) { - - if ( targetObject[ objectIndex ] === undefined ) { - - console.error( " trying to bind to objectIndex of objectName, but is undefined:", this, targetObject ); - return; - - } - - targetObject = targetObject[ objectIndex ]; - - } - - } - - // resolve property - var nodeProperty = targetObject[ propertyName ]; - - if ( nodeProperty === undefined ) { - - var nodeName = parsedPath.nodeName; - - console.error( " trying to update property for track: " + nodeName + - '.' + propertyName + " but it wasn't found.", targetObject ); - return; - - } - - // determine versioning scheme - var versioning = this.Versioning.None; - - if ( targetObject.needsUpdate !== undefined ) { // material - - versioning = this.Versioning.NeedsUpdate; - this.targetObject = targetObject; - - } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform - - versioning = this.Versioning.MatrixWorldNeedsUpdate; - this.targetObject = targetObject; - - } - - // determine how the property gets bound - var bindingType = this.BindingType.Direct; - - if ( propertyIndex !== undefined ) { - // access a sub element of the property array (only primitives are supported right now) - - if ( propertyName === "morphTargetInfluences" ) { - // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer. - - // support resolving morphTarget names into indices. - if ( ! targetObject.geometry ) { - - console.error( ' can not bind to morphTargetInfluences becasuse node does not have a geometry', this ); - return; - - } - - if ( ! targetObject.geometry.morphTargets ) { - - console.error( ' can not bind to morphTargetInfluences becasuse node does not have a geometry.morphTargets', this ); - return; - - } - - for ( var i = 0; i < this.node.geometry.morphTargets.length; i ++ ) { - - if ( targetObject.geometry.morphTargets[ i ].name === propertyIndex ) { - - propertyIndex = i; - break; - - } - - } - - } - - bindingType = this.BindingType.ArrayElement; - - this.resolvedProperty = nodeProperty; - this.propertyIndex = propertyIndex; - - } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) { - // must use copy for Object3D.Euler/Quaternion - - bindingType = this.BindingType.HasFromToArray; - - this.resolvedProperty = nodeProperty; - - } else if ( nodeProperty.length !== undefined ) { - - bindingType = this.BindingType.EntireArray; - - this.resolvedProperty = nodeProperty; + return new PropertyBinding( root, path, parsedPath ); } else { - this.propertyName = propertyName; + return new PropertyBinding.Composite( root, path, parsedPath ); } - // select getter / setter - this.getValue = this.GetterByBindingType[ bindingType ]; - this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ]; - }, - unbind: function() { + parseTrackName: function () { - this.node = null; + // Parent directories, delimited by '/' or ':'. Currently unused, but must + // be matched to parse the rest of the track name. + var directoryRe = /((?:[\w-]+[\/:])*)/; - // back to the prototype version of getValue / setValue - // note: avoiding to mutate the shape of 'this' via 'delete' - this.getValue = this._getValue_unbound; - this.setValue = this._setValue_unbound; + // Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'. + var nodeRe = /([\w-\.]+)?/; + + // Object on target node, and accessor. Name may contain only word + // characters. Accessor may contain any character except closing bracket. + var objectRe = /(?:\.([\w-]+)(?:\[(.+)\])?)?/; + + // Property and accessor. May contain only word characters. Accessor may + // contain any non-bracket characters. + var propertyRe = /\.([\w-]+)(?:\[(.+)\])?/; + + var trackRe = new RegExp('' + + '^' + + directoryRe.source + + nodeRe.source + + objectRe.source + + propertyRe.source + + '$' + ); + + var supportedObjectNames = [ 'material', 'materials', 'bones' ]; + + return function ( trackName ) { + + var matches = trackRe.exec( trackName ); + + if ( ! matches ) { + + throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName ); + + } + + var results = { + // directoryName: matches[ 1 ], // (tschw) currently unused + nodeName: matches[ 2 ], + objectName: matches[ 3 ], + objectIndex: matches[ 4 ], + propertyName: matches[ 5 ], // required + propertyIndex: matches[ 6 ] + }; + + var lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' ); + + if ( lastDot !== undefined && lastDot !== -1 ) { + + var objectName = results.nodeName.substring( lastDot + 1 ); + + // Object names must be checked against a whitelist. Otherwise, there + // is no way to parse 'foo.bar.baz': 'baz' must be a property, but + // 'bar' could be the objectName, or part of a nodeName (which can + // include '.' characters). + if ( supportedObjectNames.indexOf( objectName ) !== -1 ) { + + results.nodeName = results.nodeName.substring( 0, lastDot ); + results.objectName = objectName; + + } + + } + + if ( results.propertyName === null || results.propertyName.length === 0 ) { + + throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName ); + + } + + return results; + + }; + + }(), + + findNode: function ( root, nodeName ) { + + if ( ! nodeName || nodeName === "" || nodeName === "root" || nodeName === "." || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) { + + return root; + + } + + // search into skeleton bones. + if ( root.skeleton ) { + + var searchSkeleton = function ( skeleton ) { + + for ( var i = 0; i < skeleton.bones.length; i ++ ) { + + var bone = skeleton.bones[ i ]; + + if ( bone.name === nodeName ) { + + return bone; + + } + + } + + return null; + + }; + + var bone = searchSkeleton( root.skeleton ); + + if ( bone ) { + + return bone; + + } + + } + + // search into node subtree. + if ( root.children ) { + + var searchNodeSubtree = function ( children ) { + + for ( var i = 0; i < children.length; i ++ ) { + + var childNode = children[ i ]; + + if ( childNode.name === nodeName || childNode.uuid === nodeName ) { + + return childNode; + + } + + var result = searchNodeSubtree( childNode.children ); + + if ( result ) return result; + + } + + return null; + + }; + + var subTreeNode = searchNodeSubtree( root.children ); + + if ( subTreeNode ) { + + return subTreeNode; + + } + + } + + return null; } - }; + } ); Object.assign( PropertyBinding.prototype, { // prototype, continued // these are used to "bind" a nonexistent property - _getValue_unavailable: function() {}, - _setValue_unavailable: function() {}, - - // initial state of these methods that calls 'bind' - _getValue_unbound: PropertyBinding.prototype.getValue, - _setValue_unbound: PropertyBinding.prototype.setValue, + _getValue_unavailable: function () {}, + _setValue_unavailable: function () {}, BindingType: { Direct: 0, @@ -36863,209 +37151,262 @@ ] - ] + ], + + getValue: function getValue_unbound( targetArray, offset ) { + + this.bind(); + this.getValue( targetArray, offset ); + + // Note: This class uses a State pattern on a per-method basis: + // 'bind' sets 'this.getValue' / 'setValue' and shadows the + // prototype version of these methods with one that represents + // the bound state. When the property is not found, the methods + // become no-ops. + + }, + + setValue: function getValue_unbound( sourceArray, offset ) { + + this.bind(); + this.setValue( sourceArray, offset ); + + }, + + // create getter / setter pair for a property in the scene graph + bind: function () { + + var targetObject = this.node, + parsedPath = this.parsedPath, + + objectName = parsedPath.objectName, + propertyName = parsedPath.propertyName, + propertyIndex = parsedPath.propertyIndex; + + if ( ! targetObject ) { + + targetObject = PropertyBinding.findNode( + this.rootNode, parsedPath.nodeName ) || this.rootNode; + + this.node = targetObject; + + } + + // set fail state so we can just 'return' on error + this.getValue = this._getValue_unavailable; + this.setValue = this._setValue_unavailable; + + // ensure there is a value node + if ( ! targetObject ) { + + console.error( " trying to update node for track: " + this.path + " but it wasn't found." ); + return; + + } + + if ( objectName ) { + + var objectIndex = parsedPath.objectIndex; + + // special cases were we need to reach deeper into the hierarchy to get the face materials.... + switch ( objectName ) { + + case 'materials': + + if ( ! targetObject.material ) { + + console.error( ' can not bind to material as node does not have a material', this ); + return; + + } + + if ( ! targetObject.material.materials ) { + + console.error( ' can not bind to material.materials as node.material does not have a materials array', this ); + return; + + } + + targetObject = targetObject.material.materials; + + break; + + case 'bones': + + if ( ! targetObject.skeleton ) { + + console.error( ' can not bind to bones as node does not have a skeleton', this ); + return; + + } + + // potential future optimization: skip this if propertyIndex is already an integer + // and convert the integer string to a true integer. + + targetObject = targetObject.skeleton.bones; + + // support resolving morphTarget names into indices. + for ( var i = 0; i < targetObject.length; i ++ ) { + + if ( targetObject[ i ].name === objectIndex ) { + + objectIndex = i; + break; + + } + + } + + break; + + default: + + if ( targetObject[ objectName ] === undefined ) { + + console.error( ' can not bind to objectName of node, undefined', this ); + return; + + } + + targetObject = targetObject[ objectName ]; + + } + + + if ( objectIndex !== undefined ) { + + if ( targetObject[ objectIndex ] === undefined ) { + + console.error( " trying to bind to objectIndex of objectName, but is undefined:", this, targetObject ); + return; + + } + + targetObject = targetObject[ objectIndex ]; + + } + + } + + // resolve property + var nodeProperty = targetObject[ propertyName ]; + + if ( nodeProperty === undefined ) { + + var nodeName = parsedPath.nodeName; + + console.error( " trying to update property for track: " + nodeName + + '.' + propertyName + " but it wasn't found.", targetObject ); + return; + + } + + // determine versioning scheme + var versioning = this.Versioning.None; + + if ( targetObject.needsUpdate !== undefined ) { // material + + versioning = this.Versioning.NeedsUpdate; + this.targetObject = targetObject; + + } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform + + versioning = this.Versioning.MatrixWorldNeedsUpdate; + this.targetObject = targetObject; + + } + + // determine how the property gets bound + var bindingType = this.BindingType.Direct; + + if ( propertyIndex !== undefined ) { + + // access a sub element of the property array (only primitives are supported right now) + + if ( propertyName === "morphTargetInfluences" ) { + + // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer. + + // support resolving morphTarget names into indices. + if ( ! targetObject.geometry ) { + + console.error( ' can not bind to morphTargetInfluences becasuse node does not have a geometry', this ); + return; + + } + + if ( ! targetObject.geometry.morphTargets ) { + + console.error( ' can not bind to morphTargetInfluences becasuse node does not have a geometry.morphTargets', this ); + return; + + } + + for ( var i = 0; i < this.node.geometry.morphTargets.length; i ++ ) { + + if ( targetObject.geometry.morphTargets[ i ].name === propertyIndex ) { + + propertyIndex = i; + break; + + } + + } + + } + + bindingType = this.BindingType.ArrayElement; + + this.resolvedProperty = nodeProperty; + this.propertyIndex = propertyIndex; + + } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) { + + // must use copy for Object3D.Euler/Quaternion + + bindingType = this.BindingType.HasFromToArray; + + this.resolvedProperty = nodeProperty; + + } else if ( Array.isArray( nodeProperty ) ) { + + bindingType = this.BindingType.EntireArray; + + this.resolvedProperty = nodeProperty; + + } else { + + this.propertyName = propertyName; + + } + + // select getter / setter + this.getValue = this.GetterByBindingType[ bindingType ]; + this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ]; + + }, + + unbind: function () { + + this.node = null; + + // back to the prototype version of getValue / setValue + // note: avoiding to mutate the shape of 'this' via 'delete' + this.getValue = this._getValue_unbound; + this.setValue = this._setValue_unbound; + + } } ); - PropertyBinding.Composite = - function( targetGroup, path, optionalParsedPath ) { + //!\ DECLARE ALIAS AFTER assign prototype ! + Object.assign( PropertyBinding.prototype, { - var parsedPath = optionalParsedPath || - PropertyBinding.parseTrackName( path ); + // initial state of these methods that calls 'bind' + _getValue_unbound: PropertyBinding.prototype.getValue, + _setValue_unbound: PropertyBinding.prototype.setValue, - this._targetGroup = targetGroup; - this._bindings = targetGroup.subscribe_( path, parsedPath ); - - }; - - PropertyBinding.Composite.prototype = { - - constructor: PropertyBinding.Composite, - - getValue: function( array, offset ) { - - this.bind(); // bind all binding - - var firstValidIndex = this._targetGroup.nCachedObjects_, - binding = this._bindings[ firstValidIndex ]; - - // and only call .getValue on the first - if ( binding !== undefined ) binding.getValue( array, offset ); - - }, - - setValue: function( array, offset ) { - - var bindings = this._bindings; - - for ( var i = this._targetGroup.nCachedObjects_, - n = bindings.length; i !== n; ++ i ) { - - bindings[ i ].setValue( array, offset ); - - } - - }, - - bind: function() { - - var bindings = this._bindings; - - for ( var i = this._targetGroup.nCachedObjects_, - n = bindings.length; i !== n; ++ i ) { - - bindings[ i ].bind(); - - } - - }, - - unbind: function() { - - var bindings = this._bindings; - - for ( var i = this._targetGroup.nCachedObjects_, - n = bindings.length; i !== n; ++ i ) { - - bindings[ i ].unbind(); - - } - - } - - }; - - PropertyBinding.create = function( root, path, parsedPath ) { - - if ( ! ( root && root.isAnimationObjectGroup ) ) { - - return new PropertyBinding( root, path, parsedPath ); - - } else { - - return new PropertyBinding.Composite( root, path, parsedPath ); - - } - - }; - - PropertyBinding.parseTrackName = function( trackName ) { - - // matches strings in the form of: - // nodeName.property - // nodeName.property[accessor] - // nodeName.material.property[accessor] - // uuid.property[accessor] - // uuid.objectName[objectIndex].propertyName[propertyIndex] - // parentName/nodeName.property - // parentName/parentName/nodeName.property[index] - // .bone[Armature.DEF_cog].position - // scene:helium_balloon_model:helium_balloon_model.position - // created and tested via https://regex101.com/#javascript - - var re = /^((?:[\w-]+[\/:])*)([\w-]+)?(?:\.([\w-]+)(?:\[(.+)\])?)?\.([\w-]+)(?:\[(.+)\])?$/; - var matches = re.exec( trackName ); - - if ( ! matches ) { - - throw new Error( "cannot parse trackName at all: " + trackName ); - - } - - var results = { - // directoryName: matches[ 1 ], // (tschw) currently unused - nodeName: matches[ 2 ], // allowed to be null, specified root node. - objectName: matches[ 3 ], - objectIndex: matches[ 4 ], - propertyName: matches[ 5 ], - propertyIndex: matches[ 6 ] // allowed to be null, specifies that the whole property is set. - }; - - if ( results.propertyName === null || results.propertyName.length === 0 ) { - - throw new Error( "can not parse propertyName from trackName: " + trackName ); - - } - - return results; - - }; - - PropertyBinding.findNode = function( root, nodeName ) { - - if ( ! nodeName || nodeName === "" || nodeName === "root" || nodeName === "." || nodeName === -1 || nodeName === root.name || nodeName === root.uuid ) { - - return root; - - } - - // search into skeleton bones. - if ( root.skeleton ) { - - var searchSkeleton = function( skeleton ) { - - for( var i = 0; i < skeleton.bones.length; i ++ ) { - - var bone = skeleton.bones[ i ]; - - if ( bone.name === nodeName ) { - - return bone; - - } - } - - return null; - - }; - - var bone = searchSkeleton( root.skeleton ); - - if ( bone ) { - - return bone; - - } - } - - // search into node subtree. - if ( root.children ) { - - var searchNodeSubtree = function( children ) { - - for( var i = 0; i < children.length; i ++ ) { - - var childNode = children[ i ]; - - if ( childNode.name === nodeName || childNode.uuid === nodeName ) { - - return childNode; - - } - - var result = searchNodeSubtree( childNode.children ); - - if ( result ) return result; - - } - - return null; - - }; - - var subTreeNode = searchNodeSubtree( root.children ); - - if ( subTreeNode ) { - - return subTreeNode; - - } - - } - - return null; - - }; + } ); /** * @@ -37128,7 +37469,7 @@ objects: { get total() { return scope._objects.length; }, - get inUse() { return this.total - scope.nCachedObjects_; } + get inUse() { return this.total - scope.nCachedObjects_; } }, get bindingsPerObject() { return scope._bindings.length; } @@ -37137,9 +37478,7 @@ } - AnimationObjectGroup.prototype = { - - constructor: AnimationObjectGroup, + Object.assign( AnimationObjectGroup.prototype, { isAnimationObjectGroup: true, @@ -37219,7 +37558,7 @@ } - } else if ( objects[ index ] !== knownObject) { + } else if ( objects[ index ] !== knownObject ) { console.error( "Different objects with the same UUID " + "detected. Clean the caches or recreate your " + @@ -37367,7 +37706,8 @@ // Internal interface used by befriended PropertyBinding.Composite: - subscribe_: function( path, parsedPath ) { + subscribe_: function ( path, parsedPath ) { + // returns an array of bindings for the given path that is changed // according to the contained objects in the group @@ -37392,13 +37732,10 @@ parsedPaths.push( parsedPath ); bindings.push( bindingsForPath ); - for ( var i = nCachedObjects, - n = objects.length; i !== n; ++ i ) { + for ( var i = nCachedObjects, n = objects.length; i !== n; ++ i ) { var object = objects[ i ]; - - bindingsForPath[ i ] = - new PropertyBinding( object, path, parsedPath ); + bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath ); } @@ -37406,7 +37743,8 @@ }, - unsubscribe_: function( path ) { + unsubscribe_: function ( path ) { + // tells the group to forget about a property path and no longer // update the array previously obtained with 'subscribe_' @@ -37437,7 +37775,7 @@ } - }; + } ); /** * @@ -37505,8 +37843,8 @@ this.repetitions = Infinity; // no. of repetitions when looping - this.paused = false; // false -> zero effective time scale - this.enabled = true; // true -> zero effective weight + this.paused = false; // true -> zero effective time scale + this.enabled = true; // false -> zero effective weight this.clampWhenFinished = false; // keep feeding the last frame? @@ -37515,9 +37853,7 @@ } - AnimationAction.prototype = { - - constructor: AnimationAction, + Object.assign( AnimationAction.prototype, { // State & Scheduling @@ -37661,7 +37997,7 @@ // Time Scale Control - // set the weight stopping any scheduled warping + // set the time scale stopping any scheduled warping // although .paused = true yields an effective time scale of zero, this // method does *not* change .paused, because it would be confusing setEffectiveTimeScale: function( timeScale ) { @@ -37768,8 +38104,18 @@ // Interna _update: function( time, deltaTime, timeDirection, accuIndex ) { + // called by the mixer + if ( ! this.enabled ) { + + // call ._updateWeight() to update ._effectiveWeight + + this._updateWeight( time ); + return; + + } + var startTime = this._startTime; if ( startTime !== null ) { @@ -38090,7 +38436,7 @@ } - }; + } ); /** * @@ -38114,259 +38460,7 @@ } - AnimationMixer.prototype = { - - constructor: AnimationMixer, - - // return an action for a clip optionally using a custom root target - // object (this method allocates a lot of dynamic memory in case a - // previously unknown clip/root combination is specified) - clipAction: function ( clip, optionalRoot ) { - - var root = optionalRoot || this._root, - rootUuid = root.uuid, - - clipObject = typeof clip === 'string' ? - AnimationClip.findByName( root, clip ) : clip, - - clipUuid = clipObject !== null ? clipObject.uuid : clip, - - actionsForClip = this._actionsByClip[ clipUuid ], - prototypeAction = null; - - if ( actionsForClip !== undefined ) { - - var existingAction = - actionsForClip.actionByRoot[ rootUuid ]; - - if ( existingAction !== undefined ) { - - return existingAction; - - } - - // we know the clip, so we don't have to parse all - // the bindings again but can just copy - prototypeAction = actionsForClip.knownActions[ 0 ]; - - // also, take the clip from the prototype action - if ( clipObject === null ) - clipObject = prototypeAction._clip; - - } - - // clip must be known when specified via string - if ( clipObject === null ) return null; - - // allocate all resources required to run it - var newAction = new AnimationAction( this, clipObject, optionalRoot ); - - this._bindAction( newAction, prototypeAction ); - - // and make the action known to the memory manager - this._addInactiveAction( newAction, clipUuid, rootUuid ); - - return newAction; - - }, - - // get an existing action - existingAction: function ( clip, optionalRoot ) { - - var root = optionalRoot || this._root, - rootUuid = root.uuid, - - clipObject = typeof clip === 'string' ? - AnimationClip.findByName( root, clip ) : clip, - - clipUuid = clipObject ? clipObject.uuid : clip, - - actionsForClip = this._actionsByClip[ clipUuid ]; - - if ( actionsForClip !== undefined ) { - - return actionsForClip.actionByRoot[ rootUuid ] || null; - - } - - return null; - - }, - - // deactivates all previously scheduled actions - stopAllAction: function () { - - var actions = this._actions, - nActions = this._nActiveActions, - bindings = this._bindings, - nBindings = this._nActiveBindings; - - this._nActiveActions = 0; - this._nActiveBindings = 0; - - for ( var i = 0; i !== nActions; ++ i ) { - - actions[ i ].reset(); - - } - - for ( var i = 0; i !== nBindings; ++ i ) { - - bindings[ i ].useCount = 0; - - } - - return this; - - }, - - // advance the time and update apply the animation - update: function ( deltaTime ) { - - deltaTime *= this.timeScale; - - var actions = this._actions, - nActions = this._nActiveActions, - - time = this.time += deltaTime, - timeDirection = Math.sign( deltaTime ), - - accuIndex = this._accuIndex ^= 1; - - // run active actions - - for ( var i = 0; i !== nActions; ++ i ) { - - var action = actions[ i ]; - - if ( action.enabled ) { - - action._update( time, deltaTime, timeDirection, accuIndex ); - - } - - } - - // update scene graph - - var bindings = this._bindings, - nBindings = this._nActiveBindings; - - for ( var i = 0; i !== nBindings; ++ i ) { - - bindings[ i ].apply( accuIndex ); - - } - - return this; - - }, - - // return this mixer's root target object - getRoot: function () { - - return this._root; - - }, - - // free all resources specific to a particular clip - uncacheClip: function ( clip ) { - - var actions = this._actions, - clipUuid = clip.uuid, - actionsByClip = this._actionsByClip, - actionsForClip = actionsByClip[ clipUuid ]; - - if ( actionsForClip !== undefined ) { - - // note: just calling _removeInactiveAction would mess up the - // iteration state and also require updating the state we can - // just throw away - - var actionsToRemove = actionsForClip.knownActions; - - for ( var i = 0, n = actionsToRemove.length; i !== n; ++ i ) { - - var action = actionsToRemove[ i ]; - - this._deactivateAction( action ); - - var cacheIndex = action._cacheIndex, - lastInactiveAction = actions[ actions.length - 1 ]; - - action._cacheIndex = null; - action._byClipCacheIndex = null; - - lastInactiveAction._cacheIndex = cacheIndex; - actions[ cacheIndex ] = lastInactiveAction; - actions.pop(); - - this._removeInactiveBindingsForAction( action ); - - } - - delete actionsByClip[ clipUuid ]; - - } - - }, - - // free all resources specific to a particular root target object - uncacheRoot: function ( root ) { - - var rootUuid = root.uuid, - actionsByClip = this._actionsByClip; - - for ( var clipUuid in actionsByClip ) { - - var actionByRoot = actionsByClip[ clipUuid ].actionByRoot, - action = actionByRoot[ rootUuid ]; - - if ( action !== undefined ) { - - this._deactivateAction( action ); - this._removeInactiveAction( action ); - - } - - } - - var bindingsByRoot = this._bindingsByRootAndName, - bindingByName = bindingsByRoot[ rootUuid ]; - - if ( bindingByName !== undefined ) { - - for ( var trackName in bindingByName ) { - - var binding = bindingByName[ trackName ]; - binding.restoreOriginalState(); - this._removeInactiveBinding( binding ); - - } - - } - - }, - - // remove a targeted clip from the cache - uncacheAction: function ( clip, optionalRoot ) { - - var action = this.existingAction( clip, optionalRoot ); - - if ( action !== null ) { - - this._deactivateAction( action ); - this._removeInactiveAction( action ); - - } - - } - - }; - - // Implementation details: - - Object.assign( AnimationMixer.prototype, { + Object.assign( AnimationMixer.prototype, EventDispatcher.prototype, { _bindAction: function ( action, prototypeAction ) { @@ -38419,8 +38513,8 @@ _propertyBindings[ i ].binding.parsedPath; binding = new PropertyMixer( - PropertyBinding.create( root, trackName, path ), - track.ValueTypeName, track.getValueSize() ); + PropertyBinding.create( root, trackName, path ), + track.ValueTypeName, track.getValueSize() ); ++ binding.referenceCount; this._addInactiveBinding( binding, rootUuid, trackName ); @@ -38449,7 +38543,7 @@ actionsForClip = this._actionsByClip[ clipUuid ]; this._bindAction( action, - actionsForClip && actionsForClip.knownActions[ 0 ] ); + actionsForClip && actionsForClip.knownActions[ 0 ] ); this._addInactiveAction( action, clipUuid, rootUuid ); @@ -38623,7 +38717,7 @@ var actionByRoot = actionsForClip.actionByRoot, - rootUuid = ( actions._localRoot || this._root ).uuid; + rootUuid = ( action._localRoot || this._root ).uuid; delete actionByRoot[ rootUuid ]; @@ -38797,8 +38891,8 @@ if ( interpolant === undefined ) { interpolant = new LinearInterpolant( - new Float32Array( 2 ), new Float32Array( 2 ), - 1, this._controlInterpolantsResultBuffer ); + new Float32Array( 2 ), new Float32Array( 2 ), + 1, this._controlInterpolantsResultBuffer ); interpolant.__cacheIndex = lastActiveIndex; interpolants[ lastActiveIndex ] = interpolant; @@ -38826,12 +38920,250 @@ }, - _controlInterpolantsResultBuffer: new Float32Array( 1 ) + _controlInterpolantsResultBuffer: new Float32Array( 1 ), + + // return an action for a clip optionally using a custom root target + // object (this method allocates a lot of dynamic memory in case a + // previously unknown clip/root combination is specified) + clipAction: function ( clip, optionalRoot ) { + + var root = optionalRoot || this._root, + rootUuid = root.uuid, + + clipObject = typeof clip === 'string' ? + AnimationClip.findByName( root, clip ) : clip, + + clipUuid = clipObject !== null ? clipObject.uuid : clip, + + actionsForClip = this._actionsByClip[ clipUuid ], + prototypeAction = null; + + if ( actionsForClip !== undefined ) { + + var existingAction = + actionsForClip.actionByRoot[ rootUuid ]; + + if ( existingAction !== undefined ) { + + return existingAction; + + } + + // we know the clip, so we don't have to parse all + // the bindings again but can just copy + prototypeAction = actionsForClip.knownActions[ 0 ]; + + // also, take the clip from the prototype action + if ( clipObject === null ) + clipObject = prototypeAction._clip; + + } + + // clip must be known when specified via string + if ( clipObject === null ) return null; + + // allocate all resources required to run it + var newAction = new AnimationAction( this, clipObject, optionalRoot ); + + this._bindAction( newAction, prototypeAction ); + + // and make the action known to the memory manager + this._addInactiveAction( newAction, clipUuid, rootUuid ); + + return newAction; + + }, + + // get an existing action + existingAction: function ( clip, optionalRoot ) { + + var root = optionalRoot || this._root, + rootUuid = root.uuid, + + clipObject = typeof clip === 'string' ? + AnimationClip.findByName( root, clip ) : clip, + + clipUuid = clipObject ? clipObject.uuid : clip, + + actionsForClip = this._actionsByClip[ clipUuid ]; + + if ( actionsForClip !== undefined ) { + + return actionsForClip.actionByRoot[ rootUuid ] || null; + + } + + return null; + + }, + + // deactivates all previously scheduled actions + stopAllAction: function () { + + var actions = this._actions, + nActions = this._nActiveActions, + bindings = this._bindings, + nBindings = this._nActiveBindings; + + this._nActiveActions = 0; + this._nActiveBindings = 0; + + for ( var i = 0; i !== nActions; ++ i ) { + + actions[ i ].reset(); + + } + + for ( var i = 0; i !== nBindings; ++ i ) { + + bindings[ i ].useCount = 0; + + } + + return this; + + }, + + // advance the time and update apply the animation + update: function ( deltaTime ) { + + deltaTime *= this.timeScale; + + var actions = this._actions, + nActions = this._nActiveActions, + + time = this.time += deltaTime, + timeDirection = Math.sign( deltaTime ), + + accuIndex = this._accuIndex ^= 1; + + // run active actions + + for ( var i = 0; i !== nActions; ++ i ) { + + var action = actions[ i ]; + + action._update( time, deltaTime, timeDirection, accuIndex ); + + } + + // update scene graph + + var bindings = this._bindings, + nBindings = this._nActiveBindings; + + for ( var i = 0; i !== nBindings; ++ i ) { + + bindings[ i ].apply( accuIndex ); + + } + + return this; + + }, + + // return this mixer's root target object + getRoot: function () { + + return this._root; + + }, + + // free all resources specific to a particular clip + uncacheClip: function ( clip ) { + + var actions = this._actions, + clipUuid = clip.uuid, + actionsByClip = this._actionsByClip, + actionsForClip = actionsByClip[ clipUuid ]; + + if ( actionsForClip !== undefined ) { + + // note: just calling _removeInactiveAction would mess up the + // iteration state and also require updating the state we can + // just throw away + + var actionsToRemove = actionsForClip.knownActions; + + for ( var i = 0, n = actionsToRemove.length; i !== n; ++ i ) { + + var action = actionsToRemove[ i ]; + + this._deactivateAction( action ); + + var cacheIndex = action._cacheIndex, + lastInactiveAction = actions[ actions.length - 1 ]; + + action._cacheIndex = null; + action._byClipCacheIndex = null; + + lastInactiveAction._cacheIndex = cacheIndex; + actions[ cacheIndex ] = lastInactiveAction; + actions.pop(); + + this._removeInactiveBindingsForAction( action ); + + } + + delete actionsByClip[ clipUuid ]; + + } + + }, + + // free all resources specific to a particular root target object + uncacheRoot: function ( root ) { + + var rootUuid = root.uuid, + actionsByClip = this._actionsByClip; + + for ( var clipUuid in actionsByClip ) { + + var actionByRoot = actionsByClip[ clipUuid ].actionByRoot, + action = actionByRoot[ rootUuid ]; + + if ( action !== undefined ) { + + this._deactivateAction( action ); + this._removeInactiveAction( action ); + + } + + } + + var bindingsByRoot = this._bindingsByRootAndName, + bindingByName = bindingsByRoot[ rootUuid ]; + + if ( bindingByName !== undefined ) { + + for ( var trackName in bindingByName ) { + + var binding = bindingByName[ trackName ]; + binding.restoreOriginalState(); + this._removeInactiveBinding( binding ); + + } + + } + + }, + + // remove a targeted clip from the cache + uncacheAction: function ( clip, optionalRoot ) { + + var action = this.existingAction( clip, optionalRoot ); + + if ( action !== null ) { + + this._deactivateAction( action ); + this._removeInactiveAction( action ); + + } + + } } ); - Object.assign( AnimationMixer.prototype, EventDispatcher.prototype ); - /** * @author mrdoob / http://mrdoob.com/ */ @@ -38868,54 +39200,57 @@ } - InstancedBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); - InstancedBufferGeometry.prototype.constructor = InstancedBufferGeometry; + InstancedBufferGeometry.prototype = Object.assign( Object.create( BufferGeometry.prototype ), { - InstancedBufferGeometry.prototype.isInstancedBufferGeometry = true; + constructor: InstancedBufferGeometry, - InstancedBufferGeometry.prototype.addGroup = function ( start, count, materialIndex ) { + isInstancedBufferGeometry: true, - this.groups.push( { + addGroup: function ( start, count, materialIndex ) { - start: start, - count: count, - materialIndex: materialIndex + this.groups.push( { - } ); + start: start, + count: count, + materialIndex: materialIndex - }; + } ); - InstancedBufferGeometry.prototype.copy = function ( source ) { + }, - var index = source.index; + copy: function ( source ) { - if ( index !== null ) { + var index = source.index; - this.setIndex( index.clone() ); + if ( index !== null ) { + + this.setIndex( index.clone() ); + + } + + var attributes = source.attributes; + + for ( var name in attributes ) { + + var attribute = attributes[ name ]; + this.addAttribute( name, attribute.clone() ); + + } + + var groups = source.groups; + + for ( var i = 0, l = groups.length; i < l; i ++ ) { + + var group = groups[ i ]; + this.addGroup( group.start, group.count, group.materialIndex ); + + } + + return this; } - var attributes = source.attributes; - - for ( var name in attributes ) { - - var attribute = attributes[ name ]; - this.addAttribute( name, attribute.clone() ); - - } - - var groups = source.groups; - - for ( var i = 0, l = groups.length; i < l; i ++ ) { - - var group = groups[ i ]; - this.addGroup( group.start, group.count, group.materialIndex ); - - } - - return this; - - }; + } ); /** * @author benaadams / https://twitter.com/ben_a_adams @@ -38933,25 +39268,34 @@ } + Object.defineProperties( InterleavedBufferAttribute.prototype, { - InterleavedBufferAttribute.prototype = { + count: { - constructor: InterleavedBufferAttribute, + get: function () { + + return this.data.count; + + } + + }, + + array: { + + get: function () { + + return this.data.array; + + } + + } + + } ); + + Object.assign( InterleavedBufferAttribute.prototype, { isInterleavedBufferAttribute: true, - get count() { - - return this.data.count; - - }, - - get array() { - - return this.data.array; - - }, - setX: function ( index, x ) { this.data.array[ index * this.data.stride + this.offset ] = x; @@ -39044,7 +39388,7 @@ } - }; + } ); /** * @author benaadams / https://twitter.com/ben_a_adams @@ -39067,17 +39411,19 @@ } - InterleavedBuffer.prototype = { + Object.defineProperty( InterleavedBuffer.prototype, 'needsUpdate', { - constructor: InterleavedBuffer, - - isInterleavedBuffer: true, - - set needsUpdate( value ) { + set: function ( value ) { if ( value === true ) this.version ++; - }, + } + + } ); + + Object.assign( InterleavedBuffer.prototype, { + + isInterleavedBuffer: true, setArray: function ( array ) { @@ -39150,7 +39496,7 @@ } - }; + } ); /** * @author benaadams / https://twitter.com/ben_a_adams @@ -39164,20 +39510,23 @@ } - InstancedInterleavedBuffer.prototype = Object.create( InterleavedBuffer.prototype ); - InstancedInterleavedBuffer.prototype.constructor = InstancedInterleavedBuffer; + InstancedInterleavedBuffer.prototype = Object.assign( Object.create( InterleavedBuffer.prototype ), { - InstancedInterleavedBuffer.prototype.isInstancedInterleavedBuffer = true; + constructor: InstancedInterleavedBuffer, - InstancedInterleavedBuffer.prototype.copy = function ( source ) { + isInstancedInterleavedBuffer: true, - InterleavedBuffer.prototype.copy.call( this, source ); + copy: function ( source ) { - this.meshPerAttribute = source.meshPerAttribute; + InterleavedBuffer.prototype.copy.call( this, source ); - return this; + this.meshPerAttribute = source.meshPerAttribute; - }; + return this; + + } + + } ); /** * @author benaadams / https://twitter.com/ben_a_adams @@ -39191,20 +39540,23 @@ } - InstancedBufferAttribute.prototype = Object.create( BufferAttribute.prototype ); - InstancedBufferAttribute.prototype.constructor = InstancedBufferAttribute; + InstancedBufferAttribute.prototype = Object.assign( Object.create( BufferAttribute.prototype ), { - InstancedBufferAttribute.prototype.isInstancedBufferAttribute = true; + constructor: InstancedBufferAttribute, - InstancedBufferAttribute.prototype.copy = function ( source ) { + isInstancedBufferAttribute: true, - BufferAttribute.prototype.copy.call( this, source ); + copy: function ( source ) { - this.meshPerAttribute = source.meshPerAttribute; + BufferAttribute.prototype.copy.call( this, source ); - return this; + this.meshPerAttribute = source.meshPerAttribute; - }; + return this; + + } + + } ); /** * @author mrdoob / http://mrdoob.com/ @@ -39265,11 +39617,7 @@ } - // - - Raycaster.prototype = { - - constructor: Raycaster, + Object.assign( Raycaster.prototype, { linePrecision: 1, @@ -39283,12 +39631,12 @@ setFromCamera: function ( coords, camera ) { - if ( (camera && camera.isPerspectiveCamera) ) { + if ( ( camera && camera.isPerspectiveCamera ) ) { this.ray.origin.setFromMatrixPosition( camera.matrixWorld ); this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize(); - } else if ( (camera && camera.isOrthographicCamera) ) { + } else if ( ( camera && camera.isOrthographicCamera ) ) { this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ); @@ -39336,7 +39684,7 @@ } - }; + } ); /** * @author alteredq / http://alteredqualia.com/ @@ -39354,13 +39702,11 @@ } - Clock.prototype = { - - constructor: Clock, + Object.assign( Clock.prototype, { start: function () { - this.startTime = ( performance || Date ).now(); + this.startTime = ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732 this.oldTime = this.startTime; this.elapsedTime = 0; @@ -39389,12 +39735,13 @@ if ( this.autoStart && ! this.running ) { this.start(); + return 0; } if ( this.running ) { - var newTime = ( performance || Date ).now(); + var newTime = ( typeof performance === 'undefined' ? Date : performance ).now(); diff = ( newTime - this.oldTime ) / 1000; this.oldTime = newTime; @@ -39407,7 +39754,7 @@ } - }; + } ); /** * @author bhouston / http://clara.io @@ -39429,9 +39776,7 @@ } - Spherical.prototype = { - - constructor: Spherical, + Object.assign( Spherical.prototype, { set: function ( radius, phi, theta ) { @@ -39489,7 +39834,7 @@ } - }; + } ); /** * @author Mugen87 / https://github.com/Mugen87 @@ -39508,9 +39853,7 @@ } - Cylindrical.prototype = { - - constructor: Cylindrical, + Object.assign( Cylindrical.prototype, { set: function ( radius, theta, y ) { @@ -39548,7 +39891,7 @@ } - }; + } ); /** * @author alteredq / http://alteredqualia.com/ @@ -40024,8 +40367,6 @@ position.needsUpdate = true; - return this; - }; }() ); @@ -40106,7 +40447,7 @@ this.cone.lookAt( vector2.sub( vector ) ); - this.cone.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + this.cone.material.color.copy( this.light.color ); }; @@ -40239,7 +40580,7 @@ var geometry = new SphereBufferGeometry( sphereSize, 4, 2 ); var material = new MeshBasicMaterial( { wireframe: true, fog: false } ); - material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + material.color.copy( this.light.color ); Mesh.call( this, geometry, material ); @@ -40282,7 +40623,7 @@ PointLightHelper.prototype.update = function () { - this.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + this.material.color.copy( this.light.color ); /* var d = this.light.distance; @@ -40304,6 +40645,7 @@ /** * @author abelnation / http://github.com/abelnation * @author Mugen87 / http://github.com/Mugen87 + * @author WestLangley / http://github.com/WestLangley */ function RectAreaLightHelper( light ) { @@ -40313,28 +40655,16 @@ this.light = light; this.light.updateMatrixWorld(); - var materialFront = new MeshBasicMaterial( { - color: light.color, - fog: false - } ); + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; - var materialBack = new MeshBasicMaterial( { - color: light.color, - fog: false, - wireframe: true - } ); + var material = new LineBasicMaterial( { color: light.color } ); var geometry = new BufferGeometry(); - geometry.addAttribute( 'position', new BufferAttribute( new Float32Array( 6 * 3 ), 3 ) ); + geometry.addAttribute( 'position', new BufferAttribute( new Float32Array( 5 * 3 ), 3 ) ); - // shows the "front" of the light, e.g. where light comes from - - this.add( new Mesh( geometry, materialFront ) ); - - // shows the "back" of the light, which does not emit light - - this.add( new Mesh( geometry, materialBack ) ); + this.add( new Line( geometry, material ) ); this.update(); @@ -40347,8 +40677,6 @@ this.children[ 0 ].geometry.dispose(); this.children[ 0 ].material.dispose(); - this.children[ 1 ].geometry.dispose(); - this.children[ 1 ].material.dispose(); }; @@ -40359,46 +40687,27 @@ return function update() { - var mesh1 = this.children[ 0 ]; - var mesh2 = this.children[ 1 ]; + var line = this.children[ 0 ]; - if ( this.light.target ) { + // update material - vector1.setFromMatrixPosition( this.light.matrixWorld ); - vector2.setFromMatrixPosition( this.light.target.matrixWorld ); - - var lookVec = vector2.clone().sub( vector1 ); - mesh1.lookAt( lookVec ); - mesh2.lookAt( lookVec ); - - } - - // update materials - - mesh1.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - mesh2.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + line.material.color.copy( this.light.color ); // calculate new dimensions of the helper var hx = this.light.width * 0.5; var hy = this.light.height * 0.5; - // because the buffer attribute is shared over both geometries, we only have to update once - - var position = mesh1.geometry.getAttribute( 'position' ); + var position = line.geometry.attributes.position; var array = position.array; - // first face + // update vertices array[ 0 ] = hx; array[ 1 ] = - hy; array[ 2 ] = 0; array[ 3 ] = hx; array[ 4 ] = hy; array[ 5 ] = 0; array[ 6 ] = - hx; array[ 7 ] = hy; array[ 8 ] = 0; - - // second face - - array[ 9 ] = - hx; array[ 10 ] = hy; array[ 11 ] = 0; - array[ 12 ] = - hx; array[ 13 ] = - hy; array[ 14 ] = 0; - array[ 15 ] = hx; array[ 16 ] = - hy; array[ 17 ] = 0; + array[ 9 ] = - hx; array[ 10 ] = - hy; array[ 11 ] = 0; + array[ 12 ] = hx; array[ 13 ] = - hy; array[ 14 ] = 0; position.needsUpdate = true; @@ -40461,8 +40770,8 @@ var colors = mesh.geometry.getAttribute( 'color' ); - color1.copy( this.light.color ).multiplyScalar( this.light.intensity ); - color2.copy( this.light.groundColor ).multiplyScalar( this.light.intensity ); + color1.copy( this.light.color ); + color2.copy( this.light.groundColor ); for ( var i = 0, l = colors.count; i < l; i ++ ) { @@ -40716,8 +41025,6 @@ position.needsUpdate = true; - return this; - }; }() ); @@ -40793,7 +41100,7 @@ var targetLine = this.children[ 1 ]; lightPlane.lookAt( v3 ); - lightPlane.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + lightPlane.material.color.copy( this.light.color ); targetLine.lookAt( v3 ); targetLine.scale.z = v3.length(); @@ -41003,10 +41310,13 @@ /** * @author mrdoob / http://mrdoob.com/ + * @author Mugen87 / http://github.com/Mugen87 */ function BoxHelper( object, color ) { + this.object = object; + if ( color === undefined ) color = 0xffff00; var indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); @@ -41018,11 +41328,9 @@ LineSegments.call( this, geometry, new LineBasicMaterial( { color: color } ) ); - if ( object !== undefined ) { + this.matrixAutoUpdate = false; - this.update( object ); - - } + this.update(); } @@ -41035,13 +41343,15 @@ return function update( object ) { - if ( object && object.isBox3 ) { + if ( object !== undefined ) { - box.copy( object ); + console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' ); - } else { + } - box.setFromObject( object ); + if ( this.object !== undefined ) { + + box.setFromObject( this.object ); } @@ -41086,6 +41396,15 @@ } )(); + BoxHelper.prototype.setFromObject = function ( object ) { + + this.object = object; + this.update(); + + return this; + + }; + /** * @author WestLangley / http://github.com/WestLangley * @author zz85 / http://github.com/zz85 @@ -41316,6 +41635,8 @@ function CatmullRomCurve3( p /* array of Vector3 */ ) { + Curve.call( this ); + this.points = p || []; this.closed = false; @@ -41407,6 +41728,8 @@ function CubicBezierCurve3( v0, v1, v2, v3 ) { + Curve.call( this ); + this.v0 = v0; this.v1 = v1; this.v2 = v2; @@ -41431,6 +41754,8 @@ function QuadraticBezierCurve3( v0, v1, v2 ) { + Curve.call( this ); + this.v0 = v0; this.v1 = v1; this.v2 = v2; @@ -41454,6 +41779,8 @@ function LineCurve3( v1, v2 ) { + Curve.call( this ); + this.v1 = v1; this.v2 = v2; @@ -41547,8 +41874,24 @@ function MeshFaceMaterial( materials ) { - console.warn( 'THREE.MeshFaceMaterial has been renamed to THREE.MultiMaterial.' ); - return new MultiMaterial( materials ); + console.warn( 'THREE.MeshFaceMaterial has been removed. Use an Array instead.' ); + return materials; + + } + + function MultiMaterial( materials ) { + + if ( materials === undefined ) materials = []; + + console.warn( 'THREE.MultiMaterial has been removed. Use an Array instead.' ); + materials.isMultiMaterial = true; + materials.materials = materials; + materials.clone = function () { + + return materials.slice(); + + }; + return materials; } @@ -41935,6 +42278,11 @@ console.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' ); return this.makeRotationFromQuaternion( q ); + }, + multiplyToArray: function () { + + console.warn( 'THREE.Matrix4: .multiplyToArray() has been removed.' ); + }, multiplyVector3: function ( vector ) { @@ -42206,6 +42554,38 @@ } ); + Object.defineProperty( Skeleton.prototype, 'useVertexTexture', { + + get: function () { + + console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' ); + + }, + set: function () { + + console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' ); + + } + + } ); + + Object.defineProperty( Curve.prototype, '__arcLengthDivisions', { + + get: function () { + + console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' ); + return this.arcLengthDivisions; + + }, + set: function ( value ) { + + console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' ); + this.arcLengthDivisions = value; + + } + + } ); + // PerspectiveCamera.prototype.setLens = function ( focalLength, filmGauge ) { @@ -42427,19 +42807,19 @@ wrapAround: { get: function () { - console.warn( 'THREE.' + this.type + ': .wrapAround has been removed.' ); + console.warn( 'THREE.Material: .wrapAround has been removed.' ); }, set: function () { - console.warn( 'THREE.' + this.type + ': .wrapAround has been removed.' ); + console.warn( 'THREE.Material: .wrapAround has been removed.' ); } }, wrapRGB: { get: function () { - console.warn( 'THREE.' + this.type + ': .wrapRGB has been removed.' ); + console.warn( 'THREE.Material: .wrapRGB has been removed.' ); return new Color(); } @@ -42488,6 +42868,13 @@ Object.assign( WebGLRenderer.prototype, { + getCurrentRenderTarget: function () { + + console.warn( 'THREE.WebGLRenderer: .getCurrentRenderTarget() is now .getRenderTarget().' ); + return this.getRenderTarget(); + + }, + supportsFloatTextures: function () { console.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \'OES_texture_float\' ).' ); @@ -42936,6 +43323,7 @@ exports.Bone = Bone; exports.Mesh = Mesh; exports.LineSegments = LineSegments; + exports.LineLoop = LineLoop; exports.Line = Line; exports.Points = Points; exports.Group = Group; @@ -42976,6 +43364,7 @@ exports.PerspectiveCamera = PerspectiveCamera; exports.OrthographicCamera = OrthographicCamera; exports.CubeCamera = CubeCamera; + exports.ArrayCamera = ArrayCamera; exports.Camera = Camera; exports.AudioListener = AudioListener; exports.PositionalAudio = PositionalAudio; @@ -43088,6 +43477,7 @@ exports.TorusGeometry = TorusGeometry; exports.TorusBufferGeometry = TorusBufferGeometry; exports.TextGeometry = TextGeometry; + exports.TextBufferGeometry = TextBufferGeometry; exports.SphereGeometry = SphereGeometry; exports.SphereBufferGeometry = SphereBufferGeometry; exports.RingGeometry = RingGeometry; @@ -43099,6 +43489,7 @@ exports.ShapeGeometry = ShapeGeometry; exports.ShapeBufferGeometry = ShapeBufferGeometry; exports.ExtrudeGeometry = ExtrudeGeometry; + exports.ExtrudeBufferGeometry = ExtrudeBufferGeometry; exports.EdgesGeometry = EdgesGeometry; exports.ConeGeometry = ConeGeometry; exports.ConeBufferGeometry = ConeBufferGeometry; @@ -43113,7 +43504,6 @@ exports.RawShaderMaterial = RawShaderMaterial; exports.ShaderMaterial = ShaderMaterial; exports.PointsMaterial = PointsMaterial; - exports.MultiMaterial = MultiMaterial; exports.MeshPhysicalMaterial = MeshPhysicalMaterial; exports.MeshStandardMaterial = MeshStandardMaterial; exports.MeshPhongMaterial = MeshPhongMaterial; @@ -43265,6 +43655,7 @@ exports.LineStrip = LineStrip; exports.LinePieces = LinePieces; exports.MeshFaceMaterial = MeshFaceMaterial; + exports.MultiMaterial = MultiMaterial; exports.PointCloud = PointCloud; exports.Particle = Particle; exports.ParticleSystem = ParticleSystem;