提交 48e43d23 编写于 作者: X xiao149

添加ThreeJs库

添加ThreeJs库
上级 2549ce2f
......@@ -8,6 +8,10 @@
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="DefaultGradleProjectSettings">
<option name="testRunner" value="GRADLE" />
<option name="delegatedBuild" value="true" />
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
......@@ -58,7 +62,7 @@
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1574840092432</updated>
<workItem from="1574840093708" duration="656000" />
<workItem from="1574840093708" duration="1181000" />
</task>
<task id="LOCAL-00001" summary="初始提交">
<created>1574840585667</created>
......@@ -67,11 +71,27 @@
<option name="project" value="LOCAL" />
<updated>1574840585667</updated>
</task>
<option name="localTasksCounter" value="2" />
<task id="LOCAL-00002" summary="初始提交">
<created>1574840864085</created>
<option name="number" value="00002" />
<option name="presentableId" value="LOCAL-00002" />
<option name="project" value="LOCAL" />
<updated>1574840864085</updated>
</task>
<option name="localTasksCounter" value="3" />
<servers />
</component>
<component name="TimeTrackingManager">
<option name="totallyTimeSpent" value="656000" />
<option name="totallyTimeSpent" value="1181000" />
</component>
<component name="TodoView">
<todo-panel id="selected-file">
<is-autoscroll-to-source value="true" />
</todo-panel>
<todo-panel id="all">
<are-packages-shown value="true" />
<is-autoscroll-to-source value="true" />
</todo-panel>
</component>
<component name="ToolWindowManager">
<frame x="-7" y="-7" width="1550" height="838" extended-state="6" />
......@@ -81,12 +101,12 @@
<window_info id="UI Designer" />
<window_info id="Capture Tool" />
<window_info id="Favorites" side_tool="true" />
<window_info content_ui="combo" id="Project" order="0" visible="true" weight="0.25" />
<window_info active="true" content_ui="combo" id="Project" order="0" visible="true" weight="0.25" />
<window_info id="Structure" order="1" side_tool="true" weight="0.25" />
<window_info anchor="bottom" id="Docker" show_stripe_button="false" />
<window_info anchor="bottom" id="Database Changes" />
<window_info active="true" anchor="bottom" id="Version Control" visible="true" weight="0.6480938" />
<window_info anchor="bottom" id="Terminal" />
<window_info anchor="bottom" id="Version Control" weight="0.6480938" />
<window_info anchor="bottom" id="Terminal" weight="0.329429" />
<window_info anchor="bottom" id="Event Log" side_tool="true" />
<window_info anchor="bottom" id="Message" order="0" />
<window_info anchor="bottom" id="Find" order="1" />
......@@ -94,7 +114,7 @@
<window_info anchor="bottom" id="Debug" order="3" weight="0.4" />
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
<window_info anchor="bottom" id="TODO" order="6" />
<window_info anchor="bottom" id="TODO" order="6" visible="true" weight="0.329429" />
<window_info anchor="right" id="Palette" />
<window_info anchor="right" id="Theme Preview" />
<window_info anchor="right" id="Maven" />
......
/**
* @author alteredq / http://alteredqualia.com/
*
* Full-screen textured quad shader
*/
THREE.CopyShader = {
uniforms: {
"tDiffuse": { value: null },
"opacity": { value: 1.0 }
},
vertexShader: [
"varying vec2 vUv;",
"void main() {",
"vUv = uv;",
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
"}"
].join( "\n" ),
fragmentShader: [
"uniform float opacity;",
"uniform sampler2D tDiffuse;",
"varying vec2 vUv;",
"void main() {",
"vec4 texel = texture2D( tDiffuse, vUv );",
"gl_FragColor = opacity * texel;",
"}"
].join( "\n" )
};
/*
* @author zz85 / https://github.com/zz85
* @author mrdoob / http://mrdoob.com
* Running this will allow you to drag three.js objects around the screen.
*/
THREE.DragControls = function ( _objects, _camera, _domElement ) {
if ( _objects instanceof THREE.Camera ) {
console.warn( 'THREE.DragControls: Constructor now expects ( objects, camera, domElement )' );
var temp = _objects; _objects = _camera; _camera = temp;
}
var _plane = new THREE.Plane();
var _raycaster = new THREE.Raycaster();
var _mouse = new THREE.Vector2();
var _offset = new THREE.Vector3();
var _intersection = new THREE.Vector3();
var _selected = null, _hovered = null;
//
var scope = this;
function activate() {
_domElement.addEventListener( 'mousemove', onDocumentMouseMove, false );
_domElement.addEventListener( 'mousedown', onDocumentMouseDown, false );
_domElement.addEventListener( 'mouseup', onDocumentMouseCancel, false );
_domElement.addEventListener( 'mouseleave', onDocumentMouseCancel, false );
_domElement.addEventListener( 'touchmove', onDocumentTouchMove, false );
_domElement.addEventListener( 'touchstart', onDocumentTouchStart, false );
_domElement.addEventListener( 'touchend', onDocumentTouchEnd, false );
}
function deactivate() {
_domElement.removeEventListener( 'mousemove', onDocumentMouseMove, false );
_domElement.removeEventListener( 'mousedown', onDocumentMouseDown, false );
_domElement.removeEventListener( 'mouseup', onDocumentMouseCancel, false );
_domElement.removeEventListener( 'mouseleave', onDocumentMouseCancel, false );
_domElement.removeEventListener( 'touchmove', onDocumentTouchMove, false );
_domElement.removeEventListener( 'touchstart', onDocumentTouchStart, false );
_domElement.removeEventListener( 'touchend', onDocumentTouchEnd, false );
}
function dispose() {
deactivate();
}
function onDocumentMouseMove( event ) {
event.preventDefault();
var rect = _domElement.getBoundingClientRect();
_mouse.x = ( ( event.clientX - rect.left ) / rect.width ) * 2 - 1;
_mouse.y = - ( ( event.clientY - rect.top ) / rect.height ) * 2 + 1;
_raycaster.setFromCamera( _mouse, _camera );
if ( _selected && scope.enabled ) {
if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) {
_selected.position.copy( _intersection.sub( _offset ) );
}
scope.dispatchEvent( { type: 'drag', object: _selected } );
return;
}
_raycaster.setFromCamera( _mouse, _camera );
var intersects = _raycaster.intersectObjects( _objects );
if ( intersects.length > 0 ) {
var object = intersects[ 0 ].object;
_plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), object.position );
if ( _hovered !== object ) {
scope.dispatchEvent( { type: 'hoveron', object: object } );
_domElement.style.cursor = 'pointer';
_hovered = object;
}
} else {
if ( _hovered !== null ) {
scope.dispatchEvent( { type: 'hoveroff', object: _hovered } );
_domElement.style.cursor = 'auto';
_hovered = null;
}
}
}
function onDocumentMouseDown( event ) {
event.preventDefault();
_raycaster.setFromCamera( _mouse, _camera );
var intersects = _raycaster.intersectObjects( _objects );
if ( intersects.length > 0 ) {
_selected = intersects[ 0 ].object;
if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) {
_offset.copy( _intersection ).sub( _selected.position );
}
_domElement.style.cursor = 'move';
scope.dispatchEvent( { type: 'dragstart', object: _selected } );
}
}
function onDocumentMouseCancel( event ) {
event.preventDefault();
if ( _selected ) {
scope.dispatchEvent( { type: 'dragend', object: _selected } );
_selected = null;
}
_domElement.style.cursor = 'auto';
}
function onDocumentTouchMove( event ) {
event.preventDefault();
event = event.changedTouches[ 0 ];
var rect = _domElement.getBoundingClientRect();
_mouse.x = ( ( event.clientX - rect.left ) / rect.width ) * 2 - 1;
_mouse.y = - ( ( event.clientY - rect.top ) / rect.height ) * 2 + 1;
_raycaster.setFromCamera( _mouse, _camera );
if ( _selected && scope.enabled ) {
if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) {
_selected.position.copy( _intersection.sub( _offset ) );
}
scope.dispatchEvent( { type: 'drag', object: _selected } );
return;
}
}
function onDocumentTouchStart( event ) {
event.preventDefault();
event = event.changedTouches[ 0 ];
var rect = _domElement.getBoundingClientRect();
_mouse.x = ( ( event.clientX - rect.left ) / rect.width ) * 2 - 1;
_mouse.y = - ( ( event.clientY - rect.top ) / rect.height ) * 2 + 1;
_raycaster.setFromCamera( _mouse, _camera );
var intersects = _raycaster.intersectObjects( _objects );
if ( intersects.length > 0 ) {
_selected = intersects[ 0 ].object;
_plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), _selected.position );
if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) {
_offset.copy( _intersection ).sub( _selected.position );
}
_domElement.style.cursor = 'move';
scope.dispatchEvent( { type: 'dragstart', object: _selected } );
}
}
function onDocumentTouchEnd( event ) {
event.preventDefault();
if ( _selected ) {
scope.dispatchEvent( { type: 'dragend', object: _selected } );
_selected = null;
}
_domElement.style.cursor = 'auto';
}
activate();
// API
this.enabled = true;
this.activate = activate;
this.deactivate = deactivate;
this.dispose = dispose;
// Backward compatibility
this.setObjects = function () {
console.error( 'THREE.DragControls: setObjects() has been removed.' );
};
this.on = function ( type, listener ) {
console.warn( 'THREE.DragControls: on() has been deprecated. Use addEventListener() instead.' );
scope.addEventListener( type, listener );
};
this.off = function ( type, listener ) {
console.warn( 'THREE.DragControls: off() has been deprecated. Use removeEventListener() instead.' );
scope.removeEventListener( type, listener );
};
this.notify = function ( type ) {
console.error( 'THREE.DragControls: notify() has been deprecated. Use dispatchEvent() instead.' );
scope.dispatchEvent( { type: type } );
};
};
THREE.DragControls.prototype = Object.create( THREE.EventDispatcher.prototype );
THREE.DragControls.prototype.constructor = THREE.DragControls;
/**
* @author alteredq / http://alteredqualia.com/
*/
THREE.EffectComposer = function ( renderer, renderTarget ) {
this.renderer = renderer;
if ( renderTarget === undefined ) {
var parameters = {
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBAFormat,
stencilBuffer: false
};
var size = renderer.getDrawingBufferSize();
renderTarget = new THREE.WebGLRenderTarget( size.width, size.height, parameters );
renderTarget.texture.name = 'EffectComposer.rt1';
}
this.renderTarget1 = renderTarget;
this.renderTarget2 = renderTarget.clone();
this.renderTarget2.texture.name = 'EffectComposer.rt2';
this.writeBuffer = this.renderTarget1;
this.readBuffer = this.renderTarget2;
this.passes = [];
// dependencies
if ( THREE.CopyShader === undefined ) {
console.error( 'THREE.EffectComposer relies on THREE.CopyShader' );
}
if ( THREE.ShaderPass === undefined ) {
console.error( 'THREE.EffectComposer relies on THREE.ShaderPass' );
}
this.copyPass = new THREE.ShaderPass( THREE.CopyShader );
};
Object.assign( THREE.EffectComposer.prototype, {
swapBuffers: function () {
var tmp = this.readBuffer;
this.readBuffer = this.writeBuffer;
this.writeBuffer = tmp;
},
addPass: function ( pass ) {
this.passes.push( pass );
var size = this.renderer.getDrawingBufferSize();
pass.setSize( size.width, size.height );
},
insertPass: function ( pass, index ) {
this.passes.splice( index, 0, pass );
},
render: function ( delta ) {
var maskActive = false;
var pass, i, il = this.passes.length;
for ( i = 0; i < il; i ++ ) {
pass = this.passes[ i ];
if ( pass.enabled === false ) continue;
pass.render( this.renderer, this.writeBuffer, this.readBuffer, delta, maskActive );
if ( pass.needsSwap ) {
if ( maskActive ) {
var context = this.renderer.context;
context.stencilFunc( context.NOTEQUAL, 1, 0xffffffff );
this.copyPass.render( this.renderer, this.writeBuffer, this.readBuffer, delta );
context.stencilFunc( context.EQUAL, 1, 0xffffffff );
}
this.swapBuffers();
}
if ( THREE.MaskPass !== undefined ) {
if ( pass instanceof THREE.MaskPass ) {
maskActive = true;
} else if ( pass instanceof THREE.ClearMaskPass ) {
maskActive = false;
}
}
}
},
reset: function ( renderTarget ) {
if ( renderTarget === undefined ) {
var size = this.renderer.getDrawingBufferSize();
renderTarget = this.renderTarget1.clone();
renderTarget.setSize( size.width, size.height );
}
this.renderTarget1.dispose();
this.renderTarget2.dispose();
this.renderTarget1 = renderTarget;
this.renderTarget2 = renderTarget.clone();
this.writeBuffer = this.renderTarget1;
this.readBuffer = this.renderTarget2;
},
setSize: function ( width, height ) {
this.renderTarget1.setSize( width, height );
this.renderTarget2.setSize( width, height );
for ( var i = 0; i < this.passes.length; i ++ ) {
this.passes[ i ].setSize( width, height );
}
}
} );
THREE.Pass = function () {
// if set to true, the pass is processed by the composer
this.enabled = true;
// if set to true, the pass indicates to swap read and write buffer after rendering
this.needsSwap = true;
// if set to true, the pass clears its buffer before rendering
this.clear = false;
// if set to true, the result of the pass is rendered to screen
this.renderToScreen = false;
};
Object.assign( THREE.Pass.prototype, {
setSize: function ( width, height ) {},
render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
console.error( 'THREE.Pass: .render() must be implemented in derived pass.' );
}
} );
此差异已折叠。
/**
* @author mrdoob / http://mrdoob.com/
* @author alteredq / http://alteredqualia.com/
*/
THREE.GeometryUtils = {
// Merge two geometries or geometry and geometry from object (using object's transform)
merge: function ( geometry1, geometry2, materialIndexOffset ) {
console.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' );
var matrix;
if ( geometry2 instanceof THREE.Mesh ) {
geometry2.matrixAutoUpdate && geometry2.updateMatrix();
matrix = geometry2.matrix;
geometry2 = geometry2.geometry;
}
geometry1.merge( geometry2, matrix, materialIndexOffset );
},
// Get random point in triangle (via barycentric coordinates)
// (uniform distribution)
// http://www.cgafaq.info/wiki/Random_Point_In_Triangle
randomPointInTriangle: function () {
var vector = new THREE.Vector3();
return function ( vectorA, vectorB, vectorC ) {
var point = new THREE.Vector3();
var a = Math.random();
var b = Math.random();
if ( ( a + b ) > 1 ) {
a = 1 - a;
b = 1 - b;
}
var c = 1 - a - b;
point.copy( vectorA );
point.multiplyScalar( a );
vector.copy( vectorB );
vector.multiplyScalar( b );
point.add( vector );
vector.copy( vectorC );
vector.multiplyScalar( c );
point.add( vector );
return point;
};
}(),
// Get random point in face (triangle)
// (uniform distribution)
randomPointInFace: function ( face, geometry ) {
var vA, vB, vC;
vA = geometry.vertices[ face.a ];
vB = geometry.vertices[ face.b ];
vC = geometry.vertices[ face.c ];
return THREE.GeometryUtils.randomPointInTriangle( vA, vB, vC );
},
// Get uniformly distributed random points in mesh
// - create array with cumulative sums of face areas
// - pick random number from 0 to total area
// - find corresponding place in area array by binary search
// - get random point in face
randomPointsInGeometry: function ( geometry, n ) {
var face, i,
faces = geometry.faces,
vertices = geometry.vertices,
il = faces.length,
totalArea = 0,
cumulativeAreas = [],
vA, vB, vC;
// precompute face areas
for ( i = 0; i < il; i ++ ) {
face = faces[ i ];
vA = vertices[ face.a ];
vB = vertices[ face.b ];
vC = vertices[ face.c ];
face._area = THREE.GeometryUtils.triangleArea( vA, vB, vC );
totalArea += face._area;
cumulativeAreas[ i ] = totalArea;
}
// binary search cumulative areas array
function binarySearchIndices( value ) {
function binarySearch( start, end ) {
// return closest larger index
// if exact number is not found
if ( end < start )
return start;
var mid = start + Math.floor( ( end - start ) / 2 );
if ( cumulativeAreas[ mid ] > value ) {
return binarySearch( start, mid - 1 );
} else if ( cumulativeAreas[ mid ] < value ) {
return binarySearch( mid + 1, end );
} else {
return mid;
}
}
var result = binarySearch( 0, cumulativeAreas.length - 1 );
return result;
}
// pick random face weighted by face area
var r, index,
result = [];
var stats = {};
for ( i = 0; i < n; i ++ ) {
r = Math.random() * totalArea;
index = binarySearchIndices( r );
result[ i ] = THREE.GeometryUtils.randomPointInFace( faces[ index ], geometry );
if ( ! stats[ index ] ) {
stats[ index ] = 1;
} else {
stats[ index ] += 1;
}
}
return result;
},
randomPointsInBufferGeometry: function ( geometry, n ) {
var i,
vertices = geometry.attributes.position.array,
totalArea = 0,
cumulativeAreas = [],
vA, vB, vC;
// precompute face areas
vA = new THREE.Vector3();
vB = new THREE.Vector3();
vC = new THREE.Vector3();
// geometry._areas = [];
var il = vertices.length / 9;
for ( i = 0; i < il; i ++ ) {
vA.set( vertices[ i * 9 + 0 ], vertices[ i * 9 + 1 ], vertices[ i * 9 + 2 ] );
vB.set( vertices[ i * 9 + 3 ], vertices[ i * 9 + 4 ], vertices[ i * 9 + 5 ] );
vC.set( vertices[ i * 9 + 6 ], vertices[ i * 9 + 7 ], vertices[ i * 9 + 8 ] );
totalArea += THREE.GeometryUtils.triangleArea( vA, vB, vC );
cumulativeAreas.push( totalArea );
}
// binary search cumulative areas array
function binarySearchIndices( value ) {
function binarySearch( start, end ) {
// return closest larger index
// if exact number is not found
if ( end < start )
return start;
var mid = start + Math.floor( ( end - start ) / 2 );
if ( cumulativeAreas[ mid ] > value ) {
return binarySearch( start, mid - 1 );
} else if ( cumulativeAreas[ mid ] < value ) {
return binarySearch( mid + 1, end );
} else {
return mid;
}
}
var result = binarySearch( 0, cumulativeAreas.length - 1 );
return result;
}
// pick random face weighted by face area
var r, index,
result = [];
for ( i = 0; i < n; i ++ ) {
r = Math.random() * totalArea;
index = binarySearchIndices( r );
// result[ i ] = THREE.GeometryUtils.randomPointInFace( faces[ index ], geometry, true );
vA.set( vertices[ index * 9 + 0 ], vertices[ index * 9 + 1 ], vertices[ index * 9 + 2 ] );
vB.set( vertices[ index * 9 + 3 ], vertices[ index * 9 + 4 ], vertices[ index * 9 + 5 ] );
vC.set( vertices[ index * 9 + 6 ], vertices[ index * 9 + 7 ], vertices[ index * 9 + 8 ] );
result[ i ] = THREE.GeometryUtils.randomPointInTriangle( vA, vB, vC );
}
return result;
},
// Get triangle area (half of parallelogram)
// http://mathworld.wolfram.com/TriangleArea.html
triangleArea: function () {
var vector1 = new THREE.Vector3();
var vector2 = new THREE.Vector3();
return function ( vectorA, vectorB, vectorC ) {
vector1.subVectors( vectorB, vectorA );
vector2.subVectors( vectorC, vectorA );
vector1.cross( vector2 );
return 0.5 * vector1.length();
};
}(),
center: function ( geometry ) {
console.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' );
return geometry.center();
}
};
/**
* @author WestLangley / http://github.com/WestLangley
*
*/
THREE.Line2 = function ( geometry, material ) {
THREE.LineSegments2.call( this );
this.type = 'Line2';
this.geometry = geometry !== undefined ? geometry : new THREE.LineGeometry();
this.material = material !== undefined ? material : new THREE.LineMaterial( { color: Math.random() * 0xffffff } );
};
THREE.Line2.prototype = Object.assign( Object.create( THREE.LineSegments2.prototype ), {
constructor: THREE.Line2,
isLine2: true,
copy: function ( source ) {
// todo
return this;
}
} );
/**
* @author WestLangley / http://github.com/WestLangley
*
*/
THREE.LineGeometry = function () {
THREE.LineSegmentsGeometry.call( this );
this.type = 'LineGeometry';
};
THREE.LineGeometry.prototype = Object.assign( Object.create( THREE.LineSegmentsGeometry.prototype ), {
constructor: THREE.LineGeometry,
isLineGeometry: true,
setPositions: function ( array ) {
// converts [ x1, y1, z1, x2, y2, z2, ... ] to pairs format
var length = array.length - 3;
var points = new Float32Array( 2 * length );
for ( var i = 0; i < length; i += 3 ) {
points[ 2 * i ] = array[ i ];
points[ 2 * i + 1 ] = array[ i + 1 ];
points[ 2 * i + 2 ] = array[ i + 2 ];
points[ 2 * i + 3 ] = array[ i + 3 ];
points[ 2 * i + 4 ] = array[ i + 4 ];
points[ 2 * i + 5 ] = array[ i + 5 ];
}
THREE.LineSegmentsGeometry.prototype.setPositions.call( this, points );
return this;
},
setColors: function ( array ) {
// converts [ r1, g1, b1, r2, g2, b2, ... ] to pairs format
var length = array.length - 3;
var colors = new Float32Array( 2 * length );
for ( var i = 0; i < length; i += 3 ) {
colors[ 2 * i ] = array[ i ];
colors[ 2 * i + 1 ] = array[ i + 1 ];
colors[ 2 * i + 2 ] = array[ i + 2 ];
colors[ 2 * i + 3 ] = array[ i + 3 ];
colors[ 2 * i + 4 ] = array[ i + 4 ];
colors[ 2 * i + 5 ] = array[ i + 5 ];
}
THREE.LineSegmentsGeometry.prototype.setColors.call( this, colors );
return this;
},
fromLine: function ( line ) {
var geometry = line.geometry;
if ( geometry.isGeometry ) {
this.setPositions( geometry.vertices );
} else if ( geometry.isBufferGeometry ) {
this.setPositions( geometry.position.array ); // assumes non-indexed
}
// set colors, maybe
return this;
},
copy: function ( source ) {
// todo
return this;
}
} );
/**
* @author WestLangley / http://github.com/WestLangley
*
* parameters = {
* color: <hex>,
* linewidth: <float>,
* dashed: <boolean>,
* dashScale: <float>,
* dashSize: <float>,
* gapSize: <float>,
* resolution: <Vector2>, // to be set by renderer
* }
*/
THREE.UniformsLib.line = {
linewidth: { value: 1 },
resolution: { value: new THREE.Vector2( 1, 1 ) },
dashScale: { value: 1 },
dashSize: { value: 1 },
gapSize: { value: 1 } // todo FIX - maybe change to totalSize
};
THREE.ShaderLib[ 'line' ] = {
uniforms: THREE.UniformsUtils.merge( [
THREE.UniformsLib.common,
THREE.UniformsLib.fog,
THREE.UniformsLib.line
] ),
vertexShader:
`
#include <common>
#include <color_pars_vertex>
#include <fog_pars_vertex>
#include <logdepthbuf_pars_vertex>
#include <clipping_planes_pars_vertex>
uniform float linewidth;
uniform vec2 resolution;
attribute vec3 instanceStart;
attribute vec3 instanceEnd;
attribute vec3 instanceColorStart;
attribute vec3 instanceColorEnd;
varying vec2 vUv;
#ifdef USE_DASH
uniform float dashScale;
attribute float instanceDistanceStart;
attribute float instanceDistanceEnd;
varying float vLineDistance;
#endif
void trimSegment( const in vec4 start, inout vec4 end ) {
// trim end segment so it terminates between the camera plane and the near plane
// conservative estimate of the near plane
float a = projectionMatrix[ 2 ][ 2 ]; // 3nd entry in 3th column
float b = projectionMatrix[ 3 ][ 2 ]; // 3nd entry in 4th column
float nearEstimate = - 0.5 * b / a;
float alpha = ( nearEstimate - start.z ) / ( end.z - start.z );
end.xyz = mix( start.xyz, end.xyz, alpha );
}
void main() {
#ifdef USE_COLOR
vColor.xyz = ( position.y < 0.5 ) ? instanceColorStart : instanceColorEnd;
#endif
#ifdef USE_DASH
vLineDistance = ( position.y < 0.5 ) ? dashScale * instanceDistanceStart : dashScale * instanceDistanceEnd;
#endif
float aspect = resolution.x / resolution.y;
vUv = uv;
// camera space
vec4 start = modelViewMatrix * vec4( instanceStart, 1.0 );
vec4 end = modelViewMatrix * vec4( instanceEnd, 1.0 );
// special case for perspective projection, and segments that terminate either in, or behind, the camera plane
// clearly the gpu firmware has a way of addressing this issue when projecting into ndc space
// but we need to perform ndc-space calculations in the shader, so we must address this issue directly
// perhaps there is a more elegant solution -- WestLangley
bool perspective = ( projectionMatrix[ 2 ][ 3 ] == - 1.0 ); // 4th entry in the 3rd column
if ( perspective ) {
if ( start.z < 0.0 && end.z >= 0.0 ) {
trimSegment( start, end );
} else if ( end.z < 0.0 && start.z >= 0.0 ) {
trimSegment( end, start );
}
}
// clip space
vec4 clipStart = projectionMatrix * start;
vec4 clipEnd = projectionMatrix * end;
// ndc space
vec2 ndcStart = clipStart.xy / clipStart.w;
vec2 ndcEnd = clipEnd.xy / clipEnd.w;
// direction
vec2 dir = ndcEnd - ndcStart;
// account for clip-space aspect ratio
dir.x *= aspect;
dir = normalize( dir );
// perpendicular to dir
vec2 offset = vec2( dir.y, - dir.x );
// undo aspect ratio adjustment
dir.x /= aspect;
offset.x /= aspect;
// sign flip
if ( position.x < 0.0 ) offset *= - 1.0;
// endcaps
if ( position.y < 0.0 ) {
offset += - dir;
} else if ( position.y > 1.0 ) {
offset += dir;
}
// adjust for linewidth
offset *= linewidth;
// adjust for clip-space to screen-space conversion // maybe resolution should be based on viewport ...
offset /= resolution.y;
// select end
vec4 clip = ( position.y < 0.5 ) ? clipStart : clipEnd;
// back to clip space
offset *= clip.w;
clip.xy += offset;
gl_Position = clip;
#include <logdepthbuf_vertex>
#include <worldpos_vertex>
#include <clipping_planes_vertex>
#include <fog_vertex>
}
`,
fragmentShader:
`
uniform vec3 diffuse;
uniform float opacity;
#ifdef USE_DASH
uniform float dashSize;
uniform float gapSize;
#endif
varying float vLineDistance;
#include <common>
#include <color_pars_fragment>
#include <fog_pars_fragment>
#include <logdepthbuf_pars_fragment>
#include <clipping_planes_pars_fragment>
varying vec2 vUv;
void main() {
#include <clipping_planes_fragment>
#ifdef USE_DASH
if ( vUv.y < 0.5 || vUv.y > 0.5 ) discard; // discard endcaps
if ( mod( vLineDistance, dashSize + gapSize ) > dashSize ) discard; // todo - FIX
#endif
if ( vUv.y < 0.5 || vUv.y > 0.5 ) {
float a = vUv.x - 0.5;
float b = vUv.y - 0.5;
float len2 = a * a + b * b;
if ( len2 > 0.25 ) discard;
}
vec4 diffuseColor = vec4( diffuse, opacity );
#include <logdepthbuf_fragment>
#include <color_fragment>
gl_FragColor = vec4( diffuseColor.rgb, diffuseColor.a );
#include <premultiplied_alpha_fragment>
#include <tonemapping_fragment>
#include <encodings_fragment>
#include <fog_fragment>
}
`
};
THREE.LineMaterial = function ( parameters ) {
THREE.ShaderMaterial.call( this, {
type: 'LineMaterial',
uniforms: THREE.UniformsUtils.clone( THREE.ShaderLib[ 'line' ].uniforms ),
vertexShader: THREE.ShaderLib[ 'line' ].vertexShader,
fragmentShader: THREE.ShaderLib[ 'line' ].fragmentShader
} );
this.dashed = false;
Object.defineProperties( this, {
color: {
enumerable: true,
get: function () {
return this.uniforms.diffuse.value;
},
set: function ( value ) {
this.uniforms.diffuse.value = value;
}
},
linewidth: {
enumerable: true,
get: function () {
return this.uniforms.linewidth.value;
},
set: function ( value ) {
this.uniforms.linewidth.value = value;
}
},
dashScale: {
enumerable: true,
get: function () {
return this.uniforms.dashScale.value;
},
set: function ( value ) {
this.uniforms.dashScale.value = value;
}
},
dashSize: {
enumerable: true,
get: function () {
return this.uniforms.dashSize.value;
},
set: function ( value ) {
this.uniforms.dashSize.value = value;
}
},
gapSize: {
enumerable: true,
get: function () {
return this.uniforms.gapSize.value;
},
set: function ( value ) {
this.uniforms.gapSize.value = value;
}
},
resolution: {
enumerable: true,
get: function () {
return this.uniforms.resolution.value;
},
set: function ( value ) {
this.uniforms.resolution.value.copy( value );
}
}
} );
this.setValues( parameters );
};
THREE.LineMaterial.prototype = Object.create( THREE.ShaderMaterial.prototype );
THREE.LineMaterial.prototype.constructor = THREE.LineMaterial;
THREE.LineMaterial.prototype.isLineMaterial = true;
THREE.LineMaterial.prototype.copy = function ( source ) {
THREE.ShaderMaterial.prototype.copy.call( this, source );
this.color.copy( source.color );
this.linewidth = source.linewidth;
this.resolution = source.resolution;
// todo
return this;
};
/**
* @author WestLangley / http://github.com/WestLangley
*
*/
THREE.LineSegments2 = function ( geometry, material ) {
THREE.Mesh.call( this );
this.type = 'LineSegments2';
this.geometry = geometry !== undefined ? geometry : new THREE.LineSegmentsGeometry();
this.material = material !== undefined ? material : new THREE.LineMaterial( { color: Math.random() * 0xffffff } );
};
THREE.LineSegments2.prototype = Object.assign( Object.create( THREE.Mesh.prototype ), {
constructor: THREE.LineSegments2,
isLineSegments2: true,
computeLineDistances: ( function () { // for backwards-compatability, but could be a method of LineSegmentsGeometry...
var start = new THREE.Vector3();
var end = new THREE.Vector3();
return function computeLineDistances() {
var geometry = this.geometry;
var instanceStart = geometry.attributes.instanceStart;
var instanceEnd = geometry.attributes.instanceEnd;
var lineDistances = new Float32Array( 2 * instanceStart.data.count );
for ( var i = 0, j = 0, l = instanceStart.data.count; i < l; i ++, j += 2 ) {
start.fromBufferAttribute( instanceStart, i );
end.fromBufferAttribute( instanceEnd, i );
lineDistances[ j ] = ( j === 0 ) ? 0 : lineDistances[ j - 1 ];
lineDistances[ j + 1 ] = lineDistances[ j ] + start.distanceTo( end );
}
var instanceDistanceBuffer = new THREE.InstancedInterleavedBuffer( lineDistances, 2, 1 ); // d0, d1
geometry.addAttribute( 'instanceDistanceStart', new THREE.InterleavedBufferAttribute( instanceDistanceBuffer, 1, 0 ) ); // d0
geometry.addAttribute( 'instanceDistanceEnd', new THREE.InterleavedBufferAttribute( instanceDistanceBuffer, 1, 1 ) ); // d1
return this;
};
}() ),
copy: function ( source ) {
// todo
return this;
}
} );
/**
* @author WestLangley / http://github.com/WestLangley
*
*/
THREE.LineSegmentsGeometry = function () {
THREE.InstancedBufferGeometry.call( this );
this.type = 'LineSegmentsGeometry';
var plane = new THREE.BufferGeometry();
var positions = [ - 1, 2, 0, 1, 2, 0, - 1, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 0, - 1, - 1, 0, 1, - 1, 0 ];
var uvs = [ 0, 1, 1, 1, 0, .5, 1, .5, 0, .5, 1, .5, 0, 0, 1, 0 ];
var index = [ 0, 2, 1, 2, 3, 1, 2, 4, 3, 4, 5, 3, 4, 6, 5, 6, 7, 5 ];
this.setIndex( index );
this.addAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );
this.addAttribute( 'uv', new THREE.Float32BufferAttribute( uvs, 2 ) );
};
THREE.LineSegmentsGeometry.prototype = Object.assign( Object.create( THREE.InstancedBufferGeometry.prototype ), {
constructor: THREE.LineSegmentsGeometry,
isLineSegmentsGeometry: true,
applyMatrix: function ( matrix ) {
var start = this.attributes.instanceStart;
var end = this.attributes.instanceEnd;
if ( start !== undefined ) {
matrix.applyToBufferAttribute( start );
matrix.applyToBufferAttribute( end );
start.data.needsUpdate = true;
}
if ( this.boundingBox !== null ) {
this.computeBoundingBox();
}
if ( this.boundingSphere !== null ) {
this.computeBoundingSphere();
}
return this;
},
setPositions: function ( array ) {
var lineSegments;
if ( array instanceof Float32Array ) {
lineSegments = array;
} else if ( Array.isArray( array ) ) {
lineSegments = new Float32Array( array );
}
var instanceBuffer = new THREE.InstancedInterleavedBuffer( lineSegments, 6, 1 ); // xyz, xyz
this.addAttribute( 'instanceStart', new THREE.InterleavedBufferAttribute( instanceBuffer, 3, 0 ) ); // xyz
this.addAttribute( 'instanceEnd', new THREE.InterleavedBufferAttribute( instanceBuffer, 3, 3 ) ); // xyz
//
this.computeBoundingBox();
this.computeBoundingSphere();
return this;
},
setColors: function ( array ) {
var colors;
if ( array instanceof Float32Array ) {
colors = array;
} else if ( Array.isArray( array ) ) {
colors = new Float32Array( array );
}
var instanceColorBuffer = new THREE.InstancedInterleavedBuffer( colors, 6, 1 ); // rgb, rgb
this.addAttribute( 'instanceColorStart', new THREE.InterleavedBufferAttribute( instanceColorBuffer, 3, 0 ) ); // rgb
this.addAttribute( 'instanceColorEnd', new THREE.InterleavedBufferAttribute( instanceColorBuffer, 3, 3 ) ); // rgb
return this;
},
fromWireframeGeometry: function ( geometry ) {
this.setPositions( geometry.attributes.position.array );
return this;
},
fromEdgesGeometry: function ( geometry ) {
this.setPositions( geometry.attributes.position.array );
return this;
},
fromMesh: function ( mesh ) {
this.fromWireframeGeometry( new THREE.WireframeGeometry( mesh.geometry ) );
// set colors, maybe
return this;
},
fromLineSegements: function ( lineSegments ) {
var geometry = lineSegments.geometry;
if ( geometry.isGeometry ) {
this.setPositions( geometry.vertices );
} else if ( geometry.isBufferGeometry ) {
this.setPositions( geometry.position.array ); // assumes non-indexed
}
// set colors, maybe
return this;
},
computeBoundingBox: function () {
var box = new THREE.Box3();
return function computeBoundingBox() {
if ( this.boundingBox === null ) {
this.boundingBox = new THREE.Box3();
}
var start = this.attributes.instanceStart;
var end = this.attributes.instanceEnd;
if ( start !== undefined && end !== undefined ) {
this.boundingBox.setFromBufferAttribute( start );
box.setFromBufferAttribute( end );
this.boundingBox.union( box );
}
};
}(),
computeBoundingSphere: function () {
var vector = new THREE.Vector3();
return function computeBoundingSphere() {
if ( this.boundingSphere === null ) {
this.boundingSphere = new THREE.Sphere();
}
if ( this.boundingBox === null ) {
this.computeBoundingBox();
}
var start = this.attributes.instanceStart;
var end = this.attributes.instanceEnd;
if ( start !== undefined && end !== undefined ) {
var center = this.boundingSphere.center;
this.boundingBox.getCenter( center );
var maxRadiusSq = 0;
for ( var i = 0, il = start.count; i < il; i ++ ) {
vector.fromBufferAttribute( start, i );
maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );
vector.fromBufferAttribute( end, i );
maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );
}
this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
if ( isNaN( this.boundingSphere.radius ) ) {
console.error( 'THREE.LineSegmentsGeometry.computeBoundingSphere(): Computed radius is NaN. The instanced position data is likely to have NaN values.', this );
}
}
};
}(),
toJSON: function () {
// todo
},
clone: function () {
// todo
},
copy: function ( source ) {
// todo
return this;
}
} );
/**
* Loads a Wavefront .mtl file specifying materials
*
* @author angelxuanchang
*/
THREE.MTLLoader = function ( manager ) {
this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
};
THREE.MTLLoader.prototype = {
constructor: THREE.MTLLoader,
/**
* Loads and parses a MTL asset from a URL.
*
* @param {String} url - URL to the MTL file.
* @param {Function} [onLoad] - Callback invoked with the loaded object.
* @param {Function} [onProgress] - Callback for download progress.
* @param {Function} [onError] - Callback for download errors.
*
* @see setPath setTexturePath
*
* @note In order for relative texture references to resolve correctly
* you must call setPath and/or setTexturePath explicitly prior to load.
*/
load: function ( url, onLoad, onProgress, onError ) {
var scope = this;
var loader = new THREE.FileLoader( this.manager );
loader.setPath( this.path );
loader.load( url, function ( text ) {
onLoad( scope.parse( text ) );
}, onProgress, onError );
},
/**
* Set base path for resolving references.
* If set this path will be prepended to each loaded and found reference.
*
* @see setTexturePath
* @param {String} path
* @return {THREE.MTLLoader}
*
* @example
* mtlLoader.setPath( 'assets/obj/' );
* mtlLoader.load( 'my.mtl', ... );
*/
setPath: function ( path ) {
this.path = path;
return this;
},
/**
* Set base path for resolving texture references.
* If set this path will be prepended found texture reference.
* If not set and setPath is, it will be used as texture base path.
*
* @see setPath
* @param {String} path
* @return {THREE.MTLLoader}
*
* @example
* mtlLoader.setPath( 'assets/obj/' );
* mtlLoader.setTexturePath( 'assets/textures/' );
* mtlLoader.load( 'my.mtl', ... );
*/
setTexturePath: function ( path ) {
this.texturePath = path;
return this;
},
setBaseUrl: function ( path ) {
console.warn( 'THREE.MTLLoader: .setBaseUrl() is deprecated. Use .setTexturePath( path ) for texture path or .setPath( path ) for general base path instead.' );
return this.setTexturePath( path );
},
setCrossOrigin: function ( value ) {
this.crossOrigin = value;
return this;
},
setMaterialOptions: function ( value ) {
this.materialOptions = value;
return this;
},
/**
* Parses a MTL file.
*
* @param {String} text - Content of MTL file
* @return {THREE.MTLLoader.MaterialCreator}
*
* @see setPath setTexturePath
*
* @note In order for relative texture references to resolve correctly
* you must call setPath and/or setTexturePath explicitly prior to parse.
*/
parse: function ( text ) {
// 换行作为分界点分割字符串
var lines = text.split( '\n' );
var info = {};
// \s 匹配任何空白字符,包括空格、制表符、换页符等等
var delimiter_pattern = /\s+/;
var materialsInfo = {};
for ( var i = 0; i < lines.length; i ++ ) {
var line = lines[ i ];
// .trim():删除字符串两端的空白字符。
line = line.trim();
if ( line.length === 0 || line.charAt( 0 ) === '#' ) {
// Blank line or comment ignore
continue;
}
// 返回空格首次出现的位置
var pos = line.indexOf( ' ' );
// 提取mtl文件属性
var key = ( pos >= 0 ) ? line.substring( 0, pos ) : line;
key = key.toLowerCase();
// 提取mtl文件属性对应值的字符串
var value = ( pos >= 0 ) ? line.substring( pos + 1 ) : '';
value = value.trim();
if ( key === 'newmtl' ) {
// New material
info = { name: value };
materialsInfo[ value ] = info;
} else if ( info ) {
if ( key === 'ka' || key === 'kd' || key === 'ks' ) {
// 分割属性值对应的字符串
var ss = value.split( delimiter_pattern, 3 );
info[ key ] = [ parseFloat( ss[ 0 ] ), parseFloat( ss[ 1 ] ), parseFloat( ss[ 2 ] ) ];
} else {
info[ key ] = value;
}
}
}
var materialCreator = new THREE.MTLLoader.MaterialCreator( this.texturePath || this.path, this.materialOptions );
materialCreator.setCrossOrigin( this.crossOrigin );
materialCreator.setManager( this.manager );
materialCreator.setMaterials( materialsInfo );
return materialCreator;
}
};
/**
* Create a new THREE-MTLLoader.MaterialCreator
* @param baseUrl - Url relative to which textures are loaded
* @param options - Set of options on how to construct the materials
* side: Which side to apply the material
* THREE.FrontSide (default), THREE.BackSide, THREE.DoubleSide
* wrap: What type of wrapping to apply for textures
* THREE.RepeatWrapping (default), THREE.ClampToEdgeWrapping, THREE.MirroredRepeatWrapping
* normalizeRGB: RGBs need to be normalized to 0-1 from 0-255
* Default: false, assumed to be already normalized
* ignoreZeroRGBs: Ignore values of RGBs (Ka,Kd,Ks) that are all 0's
* Default: false
* @constructor
*/
THREE.MTLLoader.MaterialCreator = function ( baseUrl, options ) {
this.baseUrl = baseUrl || '';
this.options = options;
this.materialsInfo = {};
this.materials = {};
this.materialsArray = [];
this.nameLookup = {};
this.side = ( this.options && this.options.side ) ? this.options.side : THREE.FrontSide;
this.wrap = ( this.options && this.options.wrap ) ? this.options.wrap : THREE.RepeatWrapping;
};
THREE.MTLLoader.MaterialCreator.prototype = {
constructor: THREE.MTLLoader.MaterialCreator,
crossOrigin: 'Anonymous',
setCrossOrigin: function ( value ) {
this.crossOrigin = value;
},
setManager: function ( value ) {
this.manager = value;
},
setMaterials: function ( materialsInfo ) {
this.materialsInfo = this.convert( materialsInfo );
this.materials = {};
this.materialsArray = [];
this.nameLookup = {};
},
convert: function ( materialsInfo ) {
if ( ! this.options ) return materialsInfo;
var converted = {};
for ( var mn in materialsInfo ) {
// Convert materials info into normalized form based on options
var mat = materialsInfo[ mn ];
var covmat = {};
converted[ mn ] = covmat;
for ( var prop in mat ) {
var save = true;
var value = mat[ prop ];
var lprop = prop.toLowerCase();
switch ( lprop ) {
case 'kd':
case 'ka':
case 'ks':
// Diffuse color (color under white light) using RGB values
if ( this.options && this.options.normalizeRGB ) {
value = [ value[ 0 ] / 255, value[ 1 ] / 255, value[ 2 ] / 255 ];
}
if ( this.options && this.options.ignoreZeroRGBs ) {
if ( value[ 0 ] === 0 && value[ 1 ] === 0 && value[ 2 ] === 0 ) {
// ignore
save = false;
}
}
break;
default:
break;
}
if ( save ) {
covmat[ lprop ] = value;
}
}
}
return converted;
},
preload: function () {
for ( var mn in this.materialsInfo ) {
this.create( mn );
}
},
getIndex: function ( materialName ) {
return this.nameLookup[ materialName ];
},
getAsArray: function () {
var index = 0;
for ( var mn in this.materialsInfo ) {
this.materialsArray[ index ] = this.create( mn );
this.nameLookup[ mn ] = index;
index ++;
}
return this.materialsArray;
},
create: function ( materialName ) {
if ( this.materials[ materialName ] === undefined ) {
this.createMaterial_( materialName );
}
return this.materials[ materialName ];
},
createMaterial_: function ( materialName ) {
// Create material
var scope = this;
var mat = this.materialsInfo[ materialName ];
var params = {
name: materialName,
side: this.side
};
function resolveURL( baseUrl, url ) {
if ( typeof url !== 'string' || url === '' )
return '';
// Absolute URL
if ( /^https?:\/\//i.test( url ) ) return url;
return baseUrl + url;
}
function setMapForType( mapType, value ) {
if ( params[ mapType ] ) return; // Keep the first encountered texture
var texParams = scope.getTextureParams( value, params );
var map = scope.loadTexture( resolveURL( scope.baseUrl, texParams.url ) );
map.repeat.copy( texParams.scale );
map.offset.copy( texParams.offset );
map.wrapS = scope.wrap;
map.wrapT = scope.wrap;
params[ mapType ] = map;
}
for ( var prop in mat ) {
var value = mat[ prop ];
var n;
if ( value === '' ) continue;
switch ( prop.toLowerCase() ) {
// Ns is material specular exponent
case 'kd':
// Diffuse color (color under white light) using RGB values
params.color = new THREE.Color().fromArray( value );
break;
case 'ks':
// Specular color (color when light is reflected from shiny surface) using RGB values
params.specular = new THREE.Color().fromArray( value );
break;
case 'map_kd':
// Diffuse texture map
setMapForType( "map", value );
break;
case 'map_ks':
// Specular map
setMapForType( "specularMap", value );
break;
case 'norm':
setMapForType( "normalMap", value );
break;
case 'map_bump':
case 'bump':
// Bump texture map
setMapForType( "bumpMap", value );
break;
case 'ns':
// The specular exponent (defines the focus of the specular highlight)
// A high exponent results in a tight, concentrated highlight. Ns values normally range from 0 to 1000.
params.shininess = parseFloat( value );
break;
case 'd':
n = parseFloat( value );
if ( n < 1 ) {
params.opacity = n;
params.transparent = true;
}
break;
case 'tr':
n = parseFloat( value );
if ( this.options && this.options.invertTrProperty ) n = 1 - n;
if ( n > 0 ) {
params.opacity = 1 - n;
params.transparent = true;
}
break;
default:
break;
}
}
this.materials[ materialName ] = new THREE.MeshPhongMaterial( params );
return this.materials[ materialName ];
},
getTextureParams: function ( value, matParams ) {
var texParams = {
scale: new THREE.Vector2( 1, 1 ),
offset: new THREE.Vector2( 0, 0 )
};
var items = value.split( /\s+/ );
var pos;
pos = items.indexOf( '-bm' );
if ( pos >= 0 ) {
matParams.bumpScale = parseFloat( items[ pos + 1 ] );
items.splice( pos, 2 );
}
pos = items.indexOf( '-s' );
if ( pos >= 0 ) {
texParams.scale.set( parseFloat( items[ pos + 1 ] ), parseFloat( items[ pos + 2 ] ) );
items.splice( pos, 4 ); // we expect 3 parameters here!
}
pos = items.indexOf( '-o' );
if ( pos >= 0 ) {
texParams.offset.set( parseFloat( items[ pos + 1 ] ), parseFloat( items[ pos + 2 ] ) );
items.splice( pos, 4 ); // we expect 3 parameters here!
}
texParams.url = items.join( ' ' ).trim();
return texParams;
},
loadTexture: function ( url, mapping, onLoad, onProgress, onError ) {
var texture;
var loader = THREE.Loader.Handlers.get( url );
var manager = ( this.manager !== undefined ) ? this.manager : THREE.DefaultLoadingManager;
if ( loader === null ) {
loader = new THREE.TextureLoader( manager );
}
if ( loader.setCrossOrigin ) loader.setCrossOrigin( this.crossOrigin );
texture = loader.load( url, onLoad, onProgress, onError );
if ( mapping !== undefined ) texture.mapping = mapping;
return texture;
}
};
/**
* @author alteredq / http://alteredqualia.com/
*/
THREE.MaskPass = function ( scene, camera ) {
THREE.Pass.call( this );
this.scene = scene;
this.camera = camera;
this.clear = true;
this.needsSwap = false;
this.inverse = false;
};
THREE.MaskPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.MaskPass,
render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
var context = renderer.context;
var state = renderer.state;
// don't update color or depth
state.buffers.color.setMask( false );
state.buffers.depth.setMask( false );
// lock buffers
state.buffers.color.setLocked( true );
state.buffers.depth.setLocked( true );
// set up stencil
var writeValue, clearValue;
if ( this.inverse ) {
writeValue = 0;
clearValue = 1;
} else {
writeValue = 1;
clearValue = 0;
}
state.buffers.stencil.setTest( true );
state.buffers.stencil.setOp( context.REPLACE, context.REPLACE, context.REPLACE );
state.buffers.stencil.setFunc( context.ALWAYS, writeValue, 0xffffffff );
state.buffers.stencil.setClear( clearValue );
// draw into the stencil buffer
renderer.render( this.scene, this.camera, readBuffer, this.clear );
renderer.render( this.scene, this.camera, writeBuffer, this.clear );
// unlock color and depth buffer for subsequent rendering
state.buffers.color.setLocked( false );
state.buffers.depth.setLocked( false );
// only render where stencil is set to 1
state.buffers.stencil.setFunc( context.EQUAL, 1, 0xffffffff ); // draw if == 1
state.buffers.stencil.setOp( context.KEEP, context.KEEP, context.KEEP );
}
} );
THREE.ClearMaskPass = function () {
THREE.Pass.call( this );
this.needsSwap = false;
};
THREE.ClearMaskPass.prototype = Object.create( THREE.Pass.prototype );
Object.assign( THREE.ClearMaskPass.prototype, {
render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
renderer.state.buffers.stencil.setTest( false );
}
} );
/**
* Modules.js是3D库区图显示模型存放的地方
*
* @author 谢宁, Created on 2018-06-07
*/
/** ***************************************************************** */
//模型材质信息
var planeMat, RackMat, RackMat2, CargoMat, CargoMat_yuanliao, CargoMat_fuliao, CargoMat_baocai, CargoMat_zhongjian, CargoMat_huagong, CargoMat_chengpin, CargoMat_qita;
//库图环境配置信息
var enable_composer, enable_pan, enable_rotate, enable_zoom;
//库区信息
var storageZoneSize = 0, storageZoneList = [];
//货架信息
var shelfSize = 0, shelfList = [];
//货位信息
var storageUnitSize = 0, storageUnitList = [];
//货物信息
var cargoSize = 0, cargoList = [], CargosExist;
var PLANE_LENGTH = 24;
var PLANE_WIDTH = 55;
var PLANE_HEIGHT = 2;
var HOLDER_LENGTH = 2;
var HOLDER_WIDTH = 2;
var HOLDER_HEIGHT = 25;
var LAYER_NUM = 3;
var COLUMN_NUM = 2;
//创建库区对象
function storageZone(StorageZoneId,StorageZoneName,
coordinateX,coordinateZ,
width,length,
textColor,fontSize,textposition)
{
this.StorageZoneId=StorageZoneId;
this.StorageZoneName=StorageZoneName;
this.coordinateX=coordinateX;
this.coordinateZ=coordinateZ;
this.width=width;
this.length=length;
this.textColor=textColor;
this.fontSize=fontSize;
this.textposition=textposition;
}
//根据库区编码获取库区对象
function getStorageZoneById(StorageZoneId) {
for(var i = 0; i < storageZoneSize; i++){
if(storageZoneList[i].StorageZoneId == StorageZoneId){
return storageZoneList[i];
}
}
}
//创建货架对象
function shelf(storageZoneId, shelfId, shelfName,
planeLength , planeWidth , planeHeight ,
holderLength , holderWidth , holderHeight ,
positionX , positionY , positionZ ,
layerNum , columnNum)
{
this.storageZoneId=storageZoneId;
this.shelfId=shelfId;
this.shelfName=shelfName;
this.planeLength=planeLength;
this.planeWidth=planeWidth;
this.planeHeight=planeHeight;
this.holderLength=holderLength;
this.holderWidth=holderWidth;
this.holderHeight=holderHeight;
this.positionX=positionX;
this.positionY=positionY;
this.positionZ=positionZ;
this.layerNum=layerNum;
this.columnNum=columnNum;
}
//根据货架编码获取货架对象
function getShelfById(shelfId) {
for(var i = 0; i < shelfSize; i++){
if(shelfList[i].shelfId == shelfId){
return shelfList[i];
}
}
}
//创建货位对象
function storageUnit(storageZoneId, shelfId, shelfName,
inLayerNum , inColumnNum ,
positionX , positionY , positionZ, storageUnitId)
{
this.storageZoneId=storageZoneId;
this.shelfId=shelfId;
this.shelfName=shelfName;
this.inLayerNum=inLayerNum;
this.inColumnNum=inColumnNum;
this.positionX=positionX;
this.positionY=positionY;
this.positionZ=positionZ;
this.storageUnitId=storageUnitId;
}
//根据货架ID、层数、列数获取货位对象
function getStorageUnitById(shelfId,inLayerNum,inColumnNum) {
for(var i = 0; i < storageUnitSize; i++){
if(storageUnitList[i].shelfId == shelfId && storageUnitList[i].inLayerNum == inLayerNum && storageUnitList[i].inColumnNum == inColumnNum){
return storageUnitList[i];
}
}
}
//根据库位编码获取货位对象
function getStorageUnitByUnitId(storageUnitId) {
for(var i = 0; i < storageUnitSize; i++){
if(storageUnitList[i].storageUnitId == storageUnitId){
return storageUnitList[i];
}
}
}
//创建货物对象
function cargo(batchNo, prodBatchNo, inBatchNo,
matId, matClassId, matName,
qty, qtyUom, qty2,
warehouseId, storageZoneId, storageUnitId,
positionX , positionY , positionZ,
length , width , height)
{
this.batchNo=batchNo;
this.prodBatchNo=prodBatchNo;
this.inBatchNo=inBatchNo;
this.matId=matId;
this.matClassId=matClassId;
this.matName=matName;
this.qtyUom=qtyUom;
this.qty2=qty2;
this.warehouseId=warehouseId;
this.storageZoneId=storageZoneId;
this.storageUnitId=storageUnitId;
this.positionX=positionX;
this.positionY=positionY;
this.positionZ=positionZ;
this.length=length;
this.width=width;
this.height=height;
}
/** 初始化材质信息 */
function initMat() {
planeMat = new THREE.MeshLambertMaterial();
RackMat = new THREE.MeshLambertMaterial();
RackMat2 = new THREE.MeshPhongMaterial({color:0x1C86EE});
CargoMat = new THREE.MeshLambertMaterial();
CargoMat_yuanliao = new THREE.MeshLambertMaterial();//原料
CargoMat_fuliao = new THREE.MeshLambertMaterial();//辅料
CargoMat_baocai = new THREE.MeshLambertMaterial();//包材
CargoMat_huagong = new THREE.MeshLambertMaterial();//化工品
CargoMat_zhongjian = new THREE.MeshLambertMaterial();//中间品
CargoMat_chengpin = new THREE.MeshLambertMaterial();//成品
CargoMat_qita = new THREE.MeshLambertMaterial();//其他
new THREE.TextureLoader().load( './ThreeJs/images/plane.png', function( map ) {
planeMat.map = map;
planeMat.transparent = true;
planeMat.opacity = 0.8;
planeMat.needsUpdate = true;
} );
new THREE.TextureLoader().load( "./ThreeJs/images/rack.png", function( map ) {
RackMat.map = map;
RackMat.needsUpdate = true;
} );
new THREE.TextureLoader().load( "./ThreeJs/images/box.png", function( map ) {
CargoMat.map = map;
CargoMat.needsUpdate = true;
} );
new THREE.TextureLoader().load( "./ThreeJs/images/原料.png", function( map ) {
CargoMat_yuanliao.map = map;
CargoMat_yuanliao.needsUpdate = true;
} );
new THREE.TextureLoader().load( "./ThreeJs/images/辅料.png", function( map ) {
CargoMat_fuliao.map = map;
CargoMat_fuliao.needsUpdate = true;
} );
new THREE.TextureLoader().load( "./ThreeJs/images/包材.png", function( map ) {
CargoMat_baocai.map = map;
CargoMat_baocai.needsUpdate = true;
} );
new THREE.TextureLoader().load( "./ThreeJs/images/化工品.png", function( map ) {
CargoMat_huagong.map = map;
CargoMat_huagong.needsUpdate = true;
} );
new THREE.TextureLoader().load( "./ThreeJs/images/中间品.png", function( map ) {
CargoMat_zhongjian.map = map;
CargoMat_zhongjian.needsUpdate = true;
} );
new THREE.TextureLoader().load( "./ThreeJs/images/成品.png", function( map ) {
CargoMat_chengpin.map = map;
CargoMat_chengpin.needsUpdate = true;
} );
new THREE.TextureLoader().load( "./ThreeJs/images/其他.png", function( map ) {
CargoMat_qita.map = map;
CargoMat_qita.needsUpdate = true;
} );
}
/* 放置天空盒 **/
// function addSkybox( size,scene ) {
// urls = [
// './BM2P/images/right.jpg', // right
// './BM2P/images/left.jpg', // left
// './BM2P/images/top.jpg', // top
// './BM2P/images/down.jpg', // bottom
// './BM2P/images/back.jpg', // back
// './BM2P/images/front.jpg' // front
// ];
// var skyboxCubemap = new THREE.CubeTextureLoader().load( urls );
// skyboxCubemap.format = THREE.RGBFormat;
//
// var skyboxShader = THREE.ShaderLib['cube'];
// skyboxShader.uniforms['tCube'].value = skyboxCubemap;
// var obj = new THREE.Mesh(
// new THREE.BoxGeometry( size, size, size ),
// new THREE.ShaderMaterial({
// fragmentShader : skyboxShader.fragmentShader,
// vertexShader : skyboxShader.vertexShader,
// uniforms : skyboxShader.uniforms,
// depthWrite : false,
// side : THREE.BackSide
// })
// );
// scene.add( obj );
// }
//region 库区
/** 放置虚线框区域和库区名称 */
function addArea(x,z,width,length,scene,name,textColor,font_size,textposition) {
var geometry = new THREE.PlaneGeometry( width, length );
var obj = new THREE.Mesh( geometry, planeMat );
obj.position.set(x,1.5,z);
obj.rotation.x = -Math.PI / 2.0;
obj.name = "库区"+"$"+name.split("$")[1];
scene.add( obj );
new THREE.FontLoader().load('./BM2P/js/FZYaoTi_Regular.json',function(font){
////加入立体文字
var text= new THREE.TextGeometry(name.split("$")[1],{
// 设定文字字体
font:font,
//尺寸
size:font_size,
//厚度
height:0.01
});
text.computeBoundingBox();
//3D文字材质
var m = new THREE.MeshStandardMaterial({color:"#" + textColor});
var mesh = new THREE.Mesh(text,m)
if(textposition == "左对齐"){
mesh.position.x = x - width/2 + 10;
}else if(textposition == "居中"){
mesh.position.x = x - 15;
}else if(textposition == "右对齐"){
mesh.position.x = x + width/2 - 60;
}
mesh.position.y = 1.3;
mesh.position.z = z + length/2 - 20;
mesh.rotation.x = -Math.PI / 2.0;
scene.add(mesh);
});
}
/** 根据3D库图库区配置表添加库区和文字 */
function addStorageZone(scene) {
var eiinfo = new EiInfo();
var ajax_callback = {
onSuccess : function(eiinfo) {
storageZoneSize = eiinfo.get("size");
for(var i = 0; i < storageZoneSize; i++){
var storageZone_obj = new storageZone(eiinfo.get("StorageZoneId")[i],
eiinfo.get("StorageZoneName")[i],
eiinfo.get("coordinateX")[i],
eiinfo.get("coordinateZ")[i],
eiinfo.get("width")[i],
eiinfo.get("length")[i],
eiinfo.get("textColor")[i],
eiinfo.get("fontSize")[i],
eiinfo.get("textposition")[i]);
storageZoneList.push(storageZone_obj);
}
},
onFail : function(eMsg) {
EFAlert( "加载库图配置失败:"+eMsg ,"错误" );
}
};
EiCommunicator.send("YMIQ083D", "queryStorageZoneConfig3D", eiinfo, ajax_callback);
for(var i = 0;i < storageZoneSize; i++){
addArea(storageZoneList[i].coordinateX,storageZoneList[i].coordinateZ,storageZoneList[i].width,storageZoneList[i].length,scene,storageZoneList[i].StorageZoneId+"$"+storageZoneList[i].StorageZoneName,storageZoneList[i].textColor,storageZoneList[i].fontSize,storageZoneList[i].textposition);
}
}
//endregion
//region 货架货位
/** 放置单层货架 */
/** x,y,z 整个模型在场景中的位置 */
/** plane_x,plane_y,plane_z 货架板面的长高宽 */
/** holder_x,holder_y,holder_z 货架支架的长高宽 */
/** scene,name,num 要添加的场景,货架的名字,单层货架的库位数量 */
function addRack(x,y,z,plane_x,plane_y,plane_z,holder_x,holder_y,holder_z,scene,name,num) {
var plane = new THREE.BoxGeometry( plane_x, plane_y, plane_z/num );
var gz = [];
for(var i = 0; i < num; i++){
gz.push( z + plane_z/num/2 + (plane_z/num)*i );
var obj = new THREE.Mesh( plane, RackMat );
obj.position.set(x , y, gz[i]) ;
var msg = name+"$"+(2-i);
var eiinfo = new EiInfo();
eiinfo.set("shelfId",msg.split("$")[1]);
eiinfo.set("inLayerNum",msg.split("$")[3]);
eiinfo.set("inColumnNum",msg.split("$")[4]);
var storageUnitId = "";
var ajax_callback = {
onSuccess : function(eiinfo) {
storageUnitId = eiinfo.get("storageUnitId");
},
onFail : function(eMsg) {
EFAlert( "加载库图货架配置失败:"+eMsg ,"错误" );
}
};
EiCommunicator.send("YMIQ083D", "queryStorageUnit", eiinfo, ajax_callback);
//添加货位
var storageUnit_obj = new storageUnit(msg.split("$")[0],
msg.split("$")[1],
msg.split("$")[2],
msg.split("$")[3],
msg.split("$")[4],
x, y, gz[i], storageUnitId);
storageUnitList.push(storageUnit_obj);
storageUnitSize++;
var Unit = getStorageUnitById(msg.split("$")[1],msg.split("$")[3],msg.split("$")[4]);
obj.name = "货位"+"$"+Unit.storageUnitId;
scene.add(obj);
}
var holder = new THREE.BoxGeometry( holder_x, holder_y, holder_z );
var obj2 = new THREE.Mesh( holder, RackMat2 );
var obj3 = new THREE.Mesh( holder, RackMat2 );
var obj4 = new THREE.Mesh( holder, RackMat2 );
var obj5 = new THREE.Mesh( holder, RackMat2 );
obj2.position.set(x-plane_x/2+holder_x/2,y-holder_y/2-plane_y/2,z+holder_z/2);
obj3.position.set(x+plane_x/2-holder_x/2,y-holder_y/2-plane_y/2,z+holder_z/2);
obj4.position.set(x-plane_x/2+holder_x/2,y-holder_y/2-plane_y/2,z+plane_z-holder_z/2);
obj5.position.set(x+plane_x/2-holder_x/2,y-holder_y/2-plane_y/2,z+plane_z-holder_z/2);
scene.add(obj2);scene.add(obj3);scene.add(obj4);scene.add(obj5);
}
/** 放置一叠货架 */
/** stack_num 货架的叠数 */
function addStackOfRack(x,y,z,plane_x,plane_y,plane_z,holder_x,holder_y,holder_z,scene,name,num,stack_num) {
for(var i = 0; i < stack_num; i++){
addRack(x,y*(i+1),z,plane_x,plane_y,plane_z,holder_x,holder_y,holder_z,scene,name+"$"+(i+1),num);
}
}
/** 根据3D库图货架配置表添加货架 */
function addShelf(scene) {
var eiinfo = new EiInfo();
var ajax_callback = {
onSuccess : function(eiinfo) {
shelfSize = eiinfo.get("size");
for(var i = 0; i < shelfSize; i++){
var shelf_obj = new shelf(eiinfo.get("StorageZoneId")[i],
eiinfo.get("shelfId")[i],
eiinfo.get("shelfName")[i],
PLANE_LENGTH,PLANE_WIDTH,PLANE_HEIGHT,
HOLDER_LENGTH,HOLDER_WIDTH,HOLDER_HEIGHT,
eiinfo.get("positionX")[i],
eiinfo.get("positionY")[i],
eiinfo.get("positionZ")[i],
LAYER_NUM,COLUMN_NUM);
shelfList.push(shelf_obj);
}
},
onFail : function(eMsg) {
EFAlert( "加载库图货架配置失败:"+eMsg ,"错误" );
}
};
EiCommunicator.send("YMIQ083D", "queryShelfConfig3D", eiinfo, ajax_callback);
for(var i = 0;i < shelfSize; i++){
addStackOfRack(shelfList[i].positionX,shelfList[i].positionY,shelfList[i].positionZ,shelfList[i].planeLength,shelfList[i].planeHeight,shelfList[i].planeWidth,shelfList[i].holderLength,shelfList[i].holderHeight,shelfList[i].holderWidth,scene,shelfList[i].storageZoneId+"$"+shelfList[i].shelfId+"$"+shelfList[i].shelfName,shelfList[i].columnNum,shelfList[i].layerNum);
}
}
//region 货物
/** 放置单个货物 */
function addCargo(x,y,z,box_x,box_y,box_z,scene,name) {
var geometry = new THREE.BoxGeometry( box_x, box_y, box_z );
var obj = new THREE.Mesh( geometry, CargoMat );
obj.position.set(x,y,z);
obj.name = name;
scene.add(obj);
}
/** 放置单个货物 */
function addOneCargo(num,floor,scene,name,matClassId) {
var geometry = new THREE.BoxGeometry( 180, 180, 180 );
var x,y,z;
switch (num) {
case 1 : x=-200;y=150+(floor-1)*180;z=200;break;
case 2 : x=0;y=150+(floor-1)*180;z=200;break;
case 3 : x=200;y=150+(floor-1)*180;z=200;break;
case 4 : x=-200;y=150+(floor-1)*180;z=0;break;
case 5 : x=0;y=150+(floor-1)*180;z=0;break;
case 6 : x=200;y=150+(floor-1)*180;z=0;break;
case 7 : x=-200;y=150+(floor-1)*180;z=-200;break;
case 8 : x=0;y=150+(floor-1)*180;z=-200;break;
case 9 : x=200;y=150+(floor-1)*180;z=-200;break;
default : x=-200;y=150+(floor-1)*180;z=200;
}
var obj;
switch (matClassId) {
case "1" : obj = new THREE.Mesh( geometry, CargoMat_yuanliao );break;
case "2" : obj = new THREE.Mesh( geometry, CargoMat_fuliao );break;
case "3" : obj = new THREE.Mesh( geometry, CargoMat_baocai );break;
case "4" : obj = new THREE.Mesh( geometry, CargoMat_huagong );break;
case "5" : obj = new THREE.Mesh( geometry, CargoMat_zhongjian );break;
case "7" : obj = new THREE.Mesh( geometry, CargoMat_chengpin );break;
case "20" : obj = new THREE.Mesh( geometry, CargoMat_qita );break;
default : obj = new THREE.Mesh( geometry, CargoMat_yuanliao )
}
obj.position.set(x,y,z);
obj.name = name;
scene.add(obj);
}
/** 查询单个货位上的货物是否存在 */
function queryCargosExist(storageZoneId,storageUnitId) {
var eiinfo = new EiInfo();
eiinfo.set("storageZoneId",storageZoneId);
eiinfo.set("storageUnitId",storageUnitId);
var ajax_callback = {
onSuccess : function(eiinfo) {
CargosExist = eiinfo.get("flag")
}
};
EiCommunicator.send("YMIQ083D", "queryCargosExist", eiinfo, ajax_callback);
}
/** 查询单个货位上的货物 */
function queryOneUnitCargos(storageUnitId) {
var eiinfo = new EiInfo();
eiinfo.set("storageUnitId",storageUnitId);
var ajax_callback = {
onSuccess : function(eiinfo) {
cargoSize = eiinfo.get("size");
for(var i = 0; i < cargoSize; i++){
var cargo_obj = new cargo(eiinfo.get("batchNo")[i],
eiinfo.get("prodBatchNo")[i],
eiinfo.get("inBatchNo")[i],
eiinfo.get("matId")[i],
eiinfo.get("matClassId")[i],
eiinfo.get("matName")[i],
eiinfo.get("qty")[i],
eiinfo.get("qtyUom")[i],
eiinfo.get("qty2")[i],
eiinfo.get("warehouseId")[i],
eiinfo.get("storageZoneId")[i],
eiinfo.get("storageUnitId")[i]);
cargoList.push(cargo_obj);
}
},
onFail : function(eMsg) {
EFAlert( "加载库图货架配置失败:"+eMsg ,"错误" );
}
};
EiCommunicator.send("YMIQ083DP", "queryOneUnitCargos", eiinfo, ajax_callback);
}
/** 添加单个货位上的货物 */
function addOneUnitCargos(shelfId,inLayerNum,inColumnNum,scene) {
var storageUnit = getStorageUnitById(shelfId,inLayerNum,inColumnNum);
var storageZoneId = storageUnit.storageZoneId;
var shelf = getShelfById(storageUnit.shelfId);
var storageUnitid = storageUnit.storageUnitId;
queryCargosExist(storageZoneId,storageUnitid);
if(CargosExist == "true"){
var x = storageUnit.positionX;
var y = storageUnit.positionY + 8 + shelf.planeHeight/2;
var z = storageUnit.positionZ;
addCargo(x,y,z,16,16,16,scene,"货物"+"$"+storageUnitid)
}
}
/** 添加货物详情 */
function addCargoDetail(storageUnitId) {
queryOneUnitCargos(storageUnitId);
if(cargoList.length != 0){
for(var i = 0; i < cargoSize; i++){
addOneCargo(i+1-parseInt(i/9)*9,parseInt(i/9)+1,scene,"货物详情"+"$"+cargoList[i].batchNo,cargoList[i].matClassId)
}
cargoList = [];
}
}
//endregion
\ No newline at end of file
/**
* @author mrdoob / http://mrdoob.com/
*/
THREE.OBJLoader = ( function () {
// o object_name | g group_name
var object_pattern = /^[og]\s*(.+)?/;
// mtllib file_reference
var material_library_pattern = /^mtllib /;
// usemtl material_name
var material_use_pattern = /^usemtl /;
function ParserState() {
var state = {
objects: [],
object: {},
vertices: [],
normals: [],
colors: [],
uvs: [],
materialLibraries: [],
startObject: function ( name, fromDeclaration ) {
// If the current object (initial from reset) is not from a g/o declaration in the parsed
// file. We need to use it for the first parsed g/o to keep things in sync.
if ( this.object && this.object.fromDeclaration === false ) {
this.object.name = name;
this.object.fromDeclaration = ( fromDeclaration !== false );
return;
}
var previousMaterial = ( this.object && typeof this.object.currentMaterial === 'function' ? this.object.currentMaterial() : undefined );
if ( this.object && typeof this.object._finalize === 'function' ) {
this.object._finalize( true );
}
this.object = {
name: name || '',
fromDeclaration: ( fromDeclaration !== false ),
geometry: {
vertices: [],
normals: [],
colors: [],
uvs: []
},
materials: [],
smooth: true,
startMaterial: function ( name, libraries ) {
var previous = this._finalize( false );
// New usemtl declaration overwrites an inherited material, except if faces were declared
// after the material, then it must be preserved for proper MultiMaterial continuation.
if ( previous && ( previous.inherited || previous.groupCount <= 0 ) ) {
this.materials.splice( previous.index, 1 );
}
var material = {
index: this.materials.length,
name: name || '',
mtllib: ( Array.isArray( libraries ) && libraries.length > 0 ? libraries[ libraries.length - 1 ] : '' ),
smooth: ( previous !== undefined ? previous.smooth : this.smooth ),
groupStart: ( previous !== undefined ? previous.groupEnd : 0 ),
groupEnd: - 1,
groupCount: - 1,
inherited: false,
clone: function ( index ) {
var cloned = {
index: ( typeof index === 'number' ? index : this.index ),
name: this.name,
mtllib: this.mtllib,
smooth: this.smooth,
groupStart: 0,
groupEnd: - 1,
groupCount: - 1,
inherited: false
};
cloned.clone = this.clone.bind( cloned );
return cloned;
}
};
this.materials.push( material );
return material;
},
currentMaterial: function () {
if ( this.materials.length > 0 ) {
return this.materials[ this.materials.length - 1 ];
}
return undefined;
},
_finalize: function ( end ) {
var lastMultiMaterial = this.currentMaterial();
if ( lastMultiMaterial && lastMultiMaterial.groupEnd === - 1 ) {
lastMultiMaterial.groupEnd = this.geometry.vertices.length / 3;
lastMultiMaterial.groupCount = lastMultiMaterial.groupEnd - lastMultiMaterial.groupStart;
lastMultiMaterial.inherited = false;
}
// Ignore objects tail materials if no face declarations followed them before a new o/g started.
if ( end && this.materials.length > 1 ) {
for ( var mi = this.materials.length - 1; mi >= 0; mi -- ) {
if ( this.materials[ mi ].groupCount <= 0 ) {
this.materials.splice( mi, 1 );
}
}
}
// Guarantee at least one empty material, this makes the creation later more straight forward.
if ( end && this.materials.length === 0 ) {
this.materials.push( {
name: '',
smooth: this.smooth
} );
}
return lastMultiMaterial;
}
};
// Inherit previous objects material.
// Spec tells us that a declared material must be set to all objects until a new material is declared.
// If a usemtl declaration is encountered while this new object is being parsed, it will
// overwrite the inherited material. Exception being that there was already face declarations
// to the inherited material, then it will be preserved for proper MultiMaterial continuation.
if ( previousMaterial && previousMaterial.name && typeof previousMaterial.clone === 'function' ) {
var declared = previousMaterial.clone( 0 );
declared.inherited = true;
this.object.materials.push( declared );
}
this.objects.push( this.object );
},
finalize: function () {
if ( this.object && typeof this.object._finalize === 'function' ) {
this.object._finalize( true );
}
},
parseVertexIndex: function ( value, len ) {
var index = parseInt( value, 10 );
return ( index >= 0 ? index - 1 : index + len / 3 ) * 3;
},
parseNormalIndex: function ( value, len ) {
var index = parseInt( value, 10 );
return ( index >= 0 ? index - 1 : index + len / 3 ) * 3;
},
parseUVIndex: function ( value, len ) {
var index = parseInt( value, 10 );
return ( index >= 0 ? index - 1 : index + len / 2 ) * 2;
},
addVertex: function ( a, b, c ) {
var src = this.vertices;
var dst = this.object.geometry.vertices;
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
},
addVertexPoint: function ( a ) {
var src = this.vertices;
var dst = this.object.geometry.vertices;
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
},
addVertexLine: function ( a ) {
var src = this.vertices;
var dst = this.object.geometry.vertices;
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
},
addNormal: function ( a, b, c ) {
var src = this.normals;
var dst = this.object.geometry.normals;
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
},
addColor: function ( a, b, c ) {
var src = this.colors;
var dst = this.object.geometry.colors;
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
},
addUV: function ( a, b, c ) {
var src = this.uvs;
var dst = this.object.geometry.uvs;
dst.push( src[ a + 0 ], src[ a + 1 ] );
dst.push( src[ b + 0 ], src[ b + 1 ] );
dst.push( src[ c + 0 ], src[ c + 1 ] );
},
addUVLine: function ( a ) {
var src = this.uvs;
var dst = this.object.geometry.uvs;
dst.push( src[ a + 0 ], src[ a + 1 ] );
},
addFace: function ( a, b, c, ua, ub, uc, na, nb, nc ) {
var vLen = this.vertices.length;
var ia = this.parseVertexIndex( a, vLen );
var ib = this.parseVertexIndex( b, vLen );
var ic = this.parseVertexIndex( c, vLen );
this.addVertex( ia, ib, ic );
if ( ua !== undefined && ua !== '' ) {
var uvLen = this.uvs.length;
ia = this.parseUVIndex( ua, uvLen );
ib = this.parseUVIndex( ub, uvLen );
ic = this.parseUVIndex( uc, uvLen );
this.addUV( ia, ib, ic );
}
if ( na !== undefined && na !== '' ) {
// Normals are many times the same. If so, skip function call and parseInt.
var nLen = this.normals.length;
ia = this.parseNormalIndex( na, nLen );
ib = na === nb ? ia : this.parseNormalIndex( nb, nLen );
ic = na === nc ? ia : this.parseNormalIndex( nc, nLen );
this.addNormal( ia, ib, ic );
}
if ( this.colors.length > 0 ) {
this.addColor( ia, ib, ic );
}
},
addPointGeometry: function ( vertices ) {
this.object.geometry.type = 'Points';
var vLen = this.vertices.length;
for ( var vi = 0, l = vertices.length; vi < l; vi ++ ) {
this.addVertexPoint( this.parseVertexIndex( vertices[ vi ], vLen ) );
}
},
addLineGeometry: function ( vertices, uvs ) {
this.object.geometry.type = 'Line';
var vLen = this.vertices.length;
var uvLen = this.uvs.length;
for ( var vi = 0, l = vertices.length; vi < l; vi ++ ) {
this.addVertexLine( this.parseVertexIndex( vertices[ vi ], vLen ) );
}
for ( var uvi = 0, l = uvs.length; uvi < l; uvi ++ ) {
this.addUVLine( this.parseUVIndex( uvs[ uvi ], uvLen ) );
}
}
};
state.startObject( '', false );
return state;
}
//
function OBJLoader( manager ) {
this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
this.materials = null;
}
OBJLoader.prototype = {
constructor: OBJLoader,
load: function ( url, onLoad, onProgress, onError ) {
var scope = this;
var loader = new THREE.FileLoader( scope.manager );
loader.setPath( this.path );
loader.load( url, function ( text ) {
onLoad( scope.parse( text ) );
}, onProgress, onError );
},
setPath: function ( value ) {
this.path = value;
return this;
},
setMaterials: function ( materials ) {
this.materials = materials;
return this;
},
parse: function ( text ) {
console.time( 'OBJLoader' );
var state = new ParserState();
if ( text.indexOf( '\r\n' ) !== - 1 ) {
// This is faster than String.split with regex that splits on both
text = text.replace( /\r\n/g, '\n' );
}
if ( text.indexOf( '\\\n' ) !== - 1 ) {
// join lines separated by a line continuation character (\)
text = text.replace( /\\\n/g, '' );
}
var lines = text.split( '\n' );
var line = '', lineFirstChar = '';
var lineLength = 0;
var result = [];
// Faster to just trim left side of the line. Use if available.
var trimLeft = ( typeof ''.trimLeft === 'function' );
for ( var i = 0, l = lines.length; i < l; i ++ ) {
line = lines[ i ];
line = trimLeft ? line.trimLeft() : line.trim();
lineLength = line.length;
if ( lineLength === 0 ) continue;
lineFirstChar = line.charAt( 0 );
// @todo invoke passed in handler if any
if ( lineFirstChar === '#' ) continue;
if ( lineFirstChar === 'v' ) {
var data = line.split( /\s+/ );
switch ( data[ 0 ] ) {
case 'v':
state.vertices.push(
parseFloat( data[ 1 ] ),
parseFloat( data[ 2 ] ),
parseFloat( data[ 3 ] )
);
if ( data.length === 8 ) {
state.colors.push(
parseFloat( data[ 4 ] ),
parseFloat( data[ 5 ] ),
parseFloat( data[ 6 ] )
);
}
break;
case 'vn':
state.normals.push(
parseFloat( data[ 1 ] ),
parseFloat( data[ 2 ] ),
parseFloat( data[ 3 ] )
);
break;
case 'vt':
state.uvs.push(
parseFloat( data[ 1 ] ),
parseFloat( data[ 2 ] )
);
break;
}
} else if ( lineFirstChar === 'f' ) {
var lineData = line.substr( 1 ).trim();
var vertexData = lineData.split( /\s+/ );
var faceVertices = [];
// Parse the face vertex data into an easy to work with format
for ( var j = 0, jl = vertexData.length; j < jl; j ++ ) {
var vertex = vertexData[ j ];
if ( vertex.length > 0 ) {
var vertexParts = vertex.split( '/' );
faceVertices.push( vertexParts );
}
}
// Draw an edge between the first vertex and all subsequent vertices to form an n-gon
var v1 = faceVertices[ 0 ];
for ( var j = 1, jl = faceVertices.length - 1; j < jl; j ++ ) {
var v2 = faceVertices[ j ];
var v3 = faceVertices[ j + 1 ];
state.addFace(
v1[ 0 ], v2[ 0 ], v3[ 0 ],
v1[ 1 ], v2[ 1 ], v3[ 1 ],
v1[ 2 ], v2[ 2 ], v3[ 2 ]
);
}
} else if ( lineFirstChar === 'l' ) {
var lineParts = line.substring( 1 ).trim().split( " " );
var lineVertices = [], lineUVs = [];
if ( line.indexOf( "/" ) === - 1 ) {
lineVertices = lineParts;
} else {
for ( var li = 0, llen = lineParts.length; li < llen; li ++ ) {
var parts = lineParts[ li ].split( "/" );
if ( parts[ 0 ] !== "" ) lineVertices.push( parts[ 0 ] );
if ( parts[ 1 ] !== "" ) lineUVs.push( parts[ 1 ] );
}
}
state.addLineGeometry( lineVertices, lineUVs );
} else if ( lineFirstChar === 'p' ) {
var lineData = line.substr( 1 ).trim();
var pointData = lineData.split( " " );
state.addPointGeometry( pointData );
} else if ( ( result = object_pattern.exec( line ) ) !== null ) {
// o object_name
// or
// g group_name
// WORKAROUND: https://bugs.chromium.org/p/v8/issues/detail?id=2869
// var name = result[ 0 ].substr( 1 ).trim();
var name = ( " " + result[ 0 ].substr( 1 ).trim() ).substr( 1 );
state.startObject( name );
} else if ( material_use_pattern.test( line ) ) {
// material
state.object.startMaterial( line.substring( 7 ).trim(), state.materialLibraries );
} else if ( material_library_pattern.test( line ) ) {
// mtl file
state.materialLibraries.push( line.substring( 7 ).trim() );
} else if ( lineFirstChar === 's' ) {
result = line.split( ' ' );
// smooth shading
// @todo Handle files that have varying smooth values for a set of faces inside one geometry,
// but does not define a usemtl for each face set.
// This should be detected and a dummy material created (later MultiMaterial and geometry groups).
// This requires some care to not create extra material on each smooth value for "normal" obj files.
// where explicit usemtl defines geometry groups.
// Example asset: examples/models/obj/cerberus/Cerberus.obj
/*
* http://paulbourke.net/dataformats/obj/
* or
* http://www.cs.utah.edu/~boulos/cs3505/obj_spec.pdf
*
* From chapter "Grouping" Syntax explanation "s group_number":
* "group_number is the smoothing group number. To turn off smoothing groups, use a value of 0 or off.
* Polygonal elements use group numbers to put elements in different smoothing groups. For free-form
* surfaces, smoothing groups are either turned on or off; there is no difference between values greater
* than 0."
*/
if ( result.length > 1 ) {
var value = result[ 1 ].trim().toLowerCase();
state.object.smooth = ( value !== '0' && value !== 'off' );
} else {
// ZBrush can produce "s" lines #11707
state.object.smooth = true;
}
var material = state.object.currentMaterial();
if ( material ) material.smooth = state.object.smooth;
} else {
// Handle null terminated files without exception
if ( line === '\0' ) continue;
throw new Error( 'THREE.OBJLoader: Unexpected line: "' + line + '"' );
}
}
state.finalize();
var container = new THREE.Group();
container.materialLibraries = [].concat( state.materialLibraries );
for ( var i = 0, l = state.objects.length; i < l; i ++ ) {
var object = state.objects[ i ];
var geometry = object.geometry;
var materials = object.materials;
var isLine = ( geometry.type === 'Line' );
var isPoints = ( geometry.type === 'Points' );
var hasVertexColors = false;
// Skip o/g line declarations that did not follow with any faces
if ( geometry.vertices.length === 0 ) continue;
var buffergeometry = new THREE.BufferGeometry();
buffergeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( geometry.vertices, 3 ) );
if ( geometry.normals.length > 0 ) {
buffergeometry.addAttribute( 'normal', new THREE.Float32BufferAttribute( geometry.normals, 3 ) );
} else {
buffergeometry.computeVertexNormals();
}
if ( geometry.colors.length > 0 ) {
hasVertexColors = true;
buffergeometry.addAttribute( 'color', new THREE.Float32BufferAttribute( geometry.colors, 3 ) );
}
if ( geometry.uvs.length > 0 ) {
buffergeometry.addAttribute( 'uv', new THREE.Float32BufferAttribute( geometry.uvs, 2 ) );
}
// Create materials
var createdMaterials = [];
for ( var mi = 0, miLen = materials.length; mi < miLen; mi ++ ) {
var sourceMaterial = materials[ mi ];
var material = undefined;
if ( this.materials !== null ) {
material = this.materials.create( sourceMaterial.name );
// mtl etc. loaders probably can't create line materials correctly, copy properties to a line material.
if ( isLine && material && ! ( material instanceof THREE.LineBasicMaterial ) ) {
var materialLine = new THREE.LineBasicMaterial();
materialLine.copy( material );
materialLine.lights = false; // TOFIX
material = materialLine;
} else if ( isPoints && material && ! ( material instanceof THREE.PointsMaterial ) ) {
var materialPoints = new THREE.PointsMaterial( { size: 10, sizeAttenuation: false } );
materialLine.copy( material );
material = materialPoints;
}
}
if ( ! material ) {
if ( isLine ) {
material = new THREE.LineBasicMaterial();
} else if ( isPoints ) {
material = new THREE.PointsMaterial( { size: 1, sizeAttenuation: false } );
} else {
material = new THREE.MeshPhongMaterial();
}
material.name = sourceMaterial.name;
}
material.flatShading = sourceMaterial.smooth ? false : true;
material.vertexColors = hasVertexColors ? THREE.VertexColors : THREE.NoColors;
createdMaterials.push( material );
}
// Create mesh
var mesh;
if ( createdMaterials.length > 1 ) {
for ( var mi = 0, miLen = materials.length; mi < miLen; mi ++ ) {
var sourceMaterial = materials[ mi ];
buffergeometry.addGroup( sourceMaterial.groupStart, sourceMaterial.groupCount, mi );
}
if ( isLine ) {
mesh = new THREE.LineSegments( buffergeometry, createdMaterials );
} else if ( isPoints ) {
mesh = new THREE.Points( buffergeometry, createdMaterials );
} else {
mesh = new THREE.Mesh( buffergeometry, createdMaterials );
}
} else {
if ( isLine ) {
mesh = new THREE.LineSegments( buffergeometry, createdMaterials[ 0 ] );
} else if ( isPoints ) {
mesh = new THREE.Points( buffergeometry, createdMaterials[ 0 ] );
} else {
mesh = new THREE.Mesh( buffergeometry, createdMaterials[ 0 ] );
}
}
mesh.name = object.name;
container.add( mesh );
}
console.timeEnd( 'OBJLoader' );
return container;
}
};
return OBJLoader;
} )();
此差异已折叠。
此差异已折叠。
/**
* @author alteredq / http://alteredqualia.com/
*/
THREE.RenderPass = function ( scene, camera, overrideMaterial, clearColor, clearAlpha ) {
THREE.Pass.call( this );
this.scene = scene;
this.camera = camera;
this.overrideMaterial = overrideMaterial;
this.clearColor = clearColor;
this.clearAlpha = ( clearAlpha !== undefined ) ? clearAlpha : 0;
this.clear = true;
this.clearDepth = false;
this.needsSwap = false;
};
THREE.RenderPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.RenderPass,
render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
var oldAutoClear = renderer.autoClear;
renderer.autoClear = false;
this.scene.overrideMaterial = this.overrideMaterial;
var oldClearColor, oldClearAlpha;
if ( this.clearColor ) {
oldClearColor = renderer.getClearColor().getHex();
oldClearAlpha = renderer.getClearAlpha();
renderer.setClearColor( this.clearColor, this.clearAlpha );
}
if ( this.clearDepth ) {
renderer.clearDepth();
}
renderer.render( this.scene, this.camera, this.renderToScreen ? null : readBuffer, this.clear );
if ( this.clearColor ) {
renderer.setClearColor( oldClearColor, oldClearAlpha );
}
this.scene.overrideMaterial = null;
renderer.autoClear = oldAutoClear;
}
} );
/**
* @author alteredq / http://alteredqualia.com/
*/
THREE.ShaderPass = function ( shader, textureID ) {
THREE.Pass.call( this );
this.textureID = ( textureID !== undefined ) ? textureID : "tDiffuse";
if ( shader instanceof THREE.ShaderMaterial ) {
this.uniforms = shader.uniforms;
this.material = shader;
} else if ( shader ) {
this.uniforms = THREE.UniformsUtils.clone( shader.uniforms );
this.material = new THREE.ShaderMaterial( {
defines: Object.assign( {}, shader.defines ),
uniforms: this.uniforms,
vertexShader: shader.vertexShader,
fragmentShader: shader.fragmentShader
} );
}
this.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
this.scene = new THREE.Scene();
this.quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null );
this.quad.frustumCulled = false; // Avoid getting clipped
this.scene.add( this.quad );
};
THREE.ShaderPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.ShaderPass,
render: function( renderer, writeBuffer, readBuffer, delta, maskActive ) {
if ( this.uniforms[ this.textureID ] ) {
this.uniforms[ this.textureID ].value = readBuffer.texture;
}
this.quad.material = this.material;
if ( this.renderToScreen ) {
renderer.render( this.scene, this.camera );
} else {
renderer.render( this.scene, this.camera, writeBuffer, this.clear );
}
}
} );
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
// stats.js - http://github.com/mrdoob/stats.js
var Stats=function(){function h(a){c.appendChild(a.dom);return a}function k(a){for(var d=0;d<c.children.length;d++)c.children[d].style.display=d===a?"block":"none";l=a}var l=0,c=document.createElement("div");c.style.cssText="position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000";c.addEventListener("click",function(a){a.preventDefault();k(++l%c.children.length)},!1);var g=(performance||Date).now(),e=g,a=0,r=h(new Stats.Panel("FPS","#0ff","#002")),f=h(new Stats.Panel("MS","#0f0","#020"));
if(self.performance&&self.performance.memory)var t=h(new Stats.Panel("MB","#f08","#201"));k(0);return{REVISION:16,dom:c,addPanel:h,showPanel:k,begin:function(){g=(performance||Date).now()},end:function(){a++;var c=(performance||Date).now();f.update(c-g,200);if(c>e+1E3&&(r.update(1E3*a/(c-e),100),e=c,a=0,t)){var d=performance.memory;t.update(d.usedJSHeapSize/1048576,d.jsHeapSizeLimit/1048576)}return c},update:function(){g=this.end()},domElement:c,setMode:k}};
Stats.Panel=function(h,k,l){var c=Infinity,g=0,e=Math.round,a=e(window.devicePixelRatio||1),r=80*a,f=48*a,t=3*a,u=2*a,d=3*a,m=15*a,n=74*a,p=30*a,q=document.createElement("canvas");q.width=r;q.height=f;q.style.cssText="width:80px;height:48px";var b=q.getContext("2d");b.font="bold "+9*a+"px Helvetica,Arial,sans-serif";b.textBaseline="top";b.fillStyle=l;b.fillRect(0,0,r,f);b.fillStyle=k;b.fillText(h,t,u);b.fillRect(d,m,n,p);b.fillStyle=l;b.globalAlpha=.9;b.fillRect(d,m,n,p);return{dom:q,update:function(f,
v){c=Math.min(c,f);g=Math.max(g,f);b.fillStyle=l;b.globalAlpha=1;b.fillRect(0,0,r,m);b.fillStyle=k;b.fillText(e(f)+" "+h+" ("+e(c)+"-"+e(g)+")",t,u);b.drawImage(q,d+a,m,n-a,p,d,m,n-a,p);b.fillRect(d+n-a,m,a,p);b.fillStyle=l;b.globalAlpha=.9;b.fillRect(d+n-a,m,a,e((1-f/v)*p))}}};"object"===typeof module&&(module.exports=Stats);
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册