three#Mesh JavaScript Examples

The following examples show how to use three#Mesh. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: hud.js    From architect3d with MIT License 6 votes vote down vote up
makeCone(item) 
	{
		var coneGeo = new CylinderGeometry(5, 0, 10);
		var coneMat = new MeshBasicMaterial({color: this.getColor()});
		var cone = new Mesh(coneGeo, coneMat);
		cone.position.copy(this.rotateVector(item));
		cone.rotation.x = -Math.PI / 2.0;
		return cone;
	}
Example #2
Source File: SkyboxScene.js    From BlueMapWeb with MIT License 6 votes vote down vote up
constructor(uniforms) {
		super();

		this.autoUpdate = false;

		Object.defineProperty(this, 'isSkyboxScene', {value: true});

		let geometry = new SphereGeometry(1, 40, 5);
		let material = new ShaderMaterial({
			uniforms: uniforms,
			vertexShader: SKY_VERTEX_SHADER,
			fragmentShader: SKY_FRAGMENT_SHADER,
			side: BackSide
		});
		let skybox = new Mesh(geometry, material);

		this.add(skybox);
	}
Example #3
Source File: CubeTexturePass.js    From threejs-tutorial with MIT License 6 votes vote down vote up
CubeTexturePass = function (camera, envMap, opacity) {
    Pass.call(this);

    this.camera = camera;

    this.needsSwap = false;

    this.cubeShader = ShaderLib["cube"];
    this.cubeMesh = new Mesh(
        new BoxBufferGeometry(10, 10, 10),
        new ShaderMaterial({
            uniforms: this.cubeShader.uniforms,
            vertexShader: this.cubeShader.vertexShader,
            fragmentShader: this.cubeShader.fragmentShader,
            depthTest: false,
            depthWrite: false,
            side: BackSide,
        })
    );

    Object.defineProperty(this.cubeMesh.material, "envMap", {
        get: function () {
            return this.uniforms.envMap.value;
        },
    });

    this.envMap = envMap;
    this.opacity = opacity !== undefined ? opacity : 1.0;

    this.cubeScene = new Scene();
    this.cubeCamera = new PerspectiveCamera();
    this.cubeScene.add(this.cubeMesh);
}
Example #4
Source File: MSDFText.js    From three-mesh-ui with MIT License 6 votes vote down vote up
//

/**
 * Creates a THREE.Plane geometry, with UVs carefully positioned to map a particular
 * glyph on the MSDF texture. Then creates a shaderMaterial with the MSDF shaders,
 * creates a THREE.Mesh, returns it.
 * @private
 */
function buildText() {

	const translatedGeom = [];

	this.inlines.forEach( ( inline, i ) => {

		translatedGeom[ i ] = new MSDFGlyph( inline, this.getFontFamily() );

		translatedGeom[ i ].translate( inline.offsetX, inline.offsetY, 0 );

	} );

	const mergedGeom = mergeBufferGeometries( translatedGeom );

	const mesh = new Mesh( mergedGeom, this.getFontMaterial() );

	return mesh;

}
Example #5
Source File: saver.js    From threejs with GNU General Public License v3.0 6 votes vote down vote up
function process(object3d, smooth, mirroredPose) {
    var material = new MeshBasicMaterial();
    var group = new Group();

    object3d.traverseVisible(function (object) {
        if (object.isMesh) {

            var exporter = new finalizeMesh();
            var geometry = exporter.parse(object);

            if (mirroredPose == true) {
              geometry = mirror(geometry)
            }

            if (smooth
                && object.name != 'baseRim'
                && object.name != 'base') {
                geometry = subdivide(geometry, smooth);
            }

            var mesh = new Mesh(geometry, material);

            group.add(mesh);
        }
    });
    return group;
}
Example #6
Source File: BlockBreak.js    From webmc with MIT License 6 votes vote down vote up
constructor (game) {
    this.game = game
    this.texture = this.game.al.get('blocksAtlasSnap')
    this.texture.magFilter = NearestFilter
    this.cursor = new Mesh(
      new BoxBufferGeometry(1.001, 1.001, 1.001),
      new MeshBasicMaterial({
        map: this.texture,
        transparent: true
      })
    )
    this.lastPos = []
    this.cursorOut = new LineSegments(
      new EdgesGeometry(this.cursor.geometry),
      new LineBasicMaterial({
        color: 0x000000
      })
    )
    this.game.scene.add(this.cursor, this.cursorOut)
    this.uv = {}
    this.isDigging = false
    this.done = true
    this.setState(0)
  }
Example #7
Source File: CubeTexturePass.js    From Computer-Graphics with MIT License 6 votes vote down vote up
constructor( camera, envMap, opacity = 1 ) {

		super();

		this.camera = camera;

		this.needsSwap = false;

		this.cubeShader = ShaderLib[ 'cube' ];
		this.cubeMesh = new Mesh(
			new BoxGeometry( 10, 10, 10 ),
			new ShaderMaterial( {
				uniforms: UniformsUtils.clone( this.cubeShader.uniforms ),
				vertexShader: this.cubeShader.vertexShader,
				fragmentShader: this.cubeShader.fragmentShader,
				depthTest: false,
				depthWrite: false,
				side: BackSide
			} )
		);

		Object.defineProperty( this.cubeMesh.material, 'envMap', {

			get: function () {

				return this.uniforms.envMap.value;

			}

		} );

		this.envMap = envMap;
		this.opacity = opacity;

		this.cubeScene = new Scene();
		this.cubeCamera = new PerspectiveCamera();
		this.cubeScene.add( this.cubeMesh );

	}
Example #8
Source File: Glitchpass.js    From r3f-website with MIT License 6 votes vote down vote up
GlitchPass = function(dt_size) {
  Pass.call(this)
  if (DigitalGlitch === undefined) console.error('THREE.GlitchPass relies on THREE.DigitalGlitch')
  var shader = DigitalGlitch
  this.uniforms = UniformsUtils.clone(shader.uniforms)
  if (dt_size === undefined) dt_size = 64
  this.uniforms['tDisp'].value = this.generateHeightmap(dt_size)
  this.material = new ShaderMaterial({
    uniforms: this.uniforms,
    vertexShader: shader.vertexShader,
    fragmentShader: shader.fragmentShader
  })
  this.camera = new OrthographicCamera(-1, 1, 1, -1, 0, 1)
  this.scene = new Scene()
  this.quad = new Mesh(new PlaneBufferGeometry(2, 2), null)
  this.quad.frustumCulled = false // Avoid getting clipped
  this.scene.add(this.quad)
  this.factor = 0
}
Example #9
Source File: Pass.js    From three-viewer with MIT License 6 votes vote down vote up
/**
	 * Sets the fullscreen material.
	 *
	 * The material will be assigned to a mesh that fills the screen. The mesh
	 * will be created once a material is assigned via this method.
	 *
	 * @protected
	 * @param {Material} material - A fullscreen material.
	 */

	setFullscreenMaterial(material) {

		let screen = this.screen;

		if(screen !== null) {

			screen.material = material;

		} else {

			screen = new Mesh(getFullscreenTriangle(), material);
			screen.frustumCulled = false;

			if(this.scene === null) {

				this.scene = new Scene();

			}

			this.scene.add(screen);
			this.screen = screen;

		}

	}
Example #10
Source File: utils.js    From cga.js with MIT License 6 votes vote down vote up
export function toMesh(obj, materialOption) {
    var renderObj = null;
    if (obj instanceof cga.Point || obj.isVec3) {
        var geometry = new BufferGeometry()
        geometry.setAttribute('position', new Float32BufferAttribute([obj.x, obj.y, obj.z], 3));
        var material = new PointsMaterial({ size: 5, sizeAttenuation: false, color: 0x0ff0f0, alphaTest: 0.9, transparent: true });
        renderObj = new Points(geometry, material);

    } else if (obj instanceof cga.Line) {
        var geometry = new Geometry()
        var v1 = obj.direction.clone().multiplyScalar(10000).add(obj.origin);
        var v2 = obj.direction.clone().multiplyScalar(-10000).add(obj.origin);
        geometry.vertices.push(v1, v2);
        var material = new LineBasicMaterial({ color: 0xffff8f });
        renderObj = new Line(geometry, material);

    } else if (obj instanceof cga.Ray) {
        var geometry = new Geometry()
        var v1 = obj.direction.clone().multiplyScalar(10000).add(obj.origin);
        geometry.vertices.push(obj.origin, v1);
        var material = new LineBasicMaterial({ color: 0xff8fff });
        renderObj = new Line(geometry, material);
    } else if (obj instanceof cga.Segment) {
        var geometry = new Geometry()
        geometry.vertices.push(obj.p0, obj.p1);
        var material = new LineBasicMaterial({ color: 0x8fffff });
        renderObj = new Line(geometry, material);
    } else if (obj instanceof cga.Triangle) {
        var geometry = new Geometry()
        geometry.vertices = [...obj];
        geometry.faces.push(new Face3(0, 1, 2))
        var material = new MeshBasicMaterial({ color: 0x8f8fff, side: DoubleSide });
        renderObj = new Mesh(geometry, material);
    }

    else if (obj instanceof cga.Polyline) {
        var geometry = new Geometry()
        geometry.vertices.push(...obj);
        var material = new LineBasicMaterial({ color: 0xff8fff });
        renderObj = new Line(geometry, material);
    } else if (obj instanceof cga.Polygon) {

    } else if (obj instanceof cga.Circle) {
        var geometry = new Geometry()
        var radius = obj.radius;
        for (let i = 0; i <= 128; i++) {
            var p = new Vector3();
            p.x = radius * Math.cos(Math.PI / 64 * i);
            p.y = radius * Math.sin(Math.PI / 64 * i);
            geometry.vertices.push(p);
        }
        var quaternion = getQuaternionForm2V(new Vector3(0, 0, 1), obj.normal);
        var mat4 = new Matrix4();
        mat4.makeRotationFromQuaternion(quaternion);
        geometry.applyMatrix(mat4);
        geometry.translate(obj.center.x, obj.center.y, obj.center.z);
        var material = new LineBasicMaterial({ color: 0x8fffff });
        renderObj = new Line(geometry, material);
        renderObj.add(new toMesh(obj.center))
        renderObj.add(new toMesh(new cga.Ray(obj.center, obj.normal)))
    }
    else if (obj instanceof cga.Disk) {
        var geometry = new CircleGeometry(obj.radius, 128)
        var material = new MeshBasicMaterial({ color: 0x8f8fff, side: DoubleSide });
        var quaternion = getQuaternionForm2V(new Vector3(0, 0, 1), obj.normal);
        var mat4 = new Matrix4();
        mat4.makeRotationFromQuaternion(quaternion);
        geometry.applyMatrix4(mat4);
        geometry.translate(obj.center.x, obj.center.y, obj.center.z);
        renderObj = new Mesh(geometry, material);
        renderObj.add(new toMesh(obj.center))
        renderObj.add(new toMesh(new cga.Ray(obj.center, obj.normal)))
    }

    return renderObj;

}
Example #11
Source File: item.js    From architect3d with MIT License 6 votes vote down vote up
/** */
	createGlow(color, opacity, ignoreDepth)
	{
		ignoreDepth = ignoreDepth || false;
		opacity = opacity || 0.2;
		var glowMaterial = new MeshBasicMaterial({color: color, blending: AdditiveBlending, opacity: 0.2, transparent: true, depthTest: !ignoreDepth});
		var glow = new Mesh(this.geometry.clone(), glowMaterial);
		glow.position.copy(this.position);
		glow.rotation.copy(this.rotation);
		glow.scale.copy(this.scale);
		return glow;
	}
Example #12
Source File: PopupMarker.js    From BlueMapVue with MIT License 6 votes vote down vote up
constructor(id, appState, events) {
        super(id);

        this.data.type = "popup";
        this.data.label = "Last Map Interaction";

        this.appState = appState;
        this.events = events;
        this.visible = false;

        this.elementObject = new CSS2DObject(htmlToElement(`<div id="bm-marker-${this.data.id}" class="bm-marker-${this.data.type}">Test</div>`));
        this.elementObject.position.set(0.5, 1, 0.5);
        this.addEventListener( 'removed', () => {
            if (this.element.parentNode) this.element.parentNode.removeChild(this.element);
        });

        let cubeGeo = new BoxGeometry(1.01, 1.01, 1.01).translate(0.5, 0.5, 0.5);
        let cubeMaterial = new MeshBasicMaterial( {color: 0xffffff, opacity: 0.5, transparent: true} );
        this.cube = new Mesh(cubeGeo, cubeMaterial);
        this.cube.onClick = evt => this.onClick(evt);

        this.add(this.elementObject);
        this.add(this.cube);

        this.animation = null;

        this.events.addEventListener('bluemapMapInteraction', this.onMapInteraction);

        window.addEventListener("mousedown", this.removeHandler);
        window.addEventListener("touchstart", this.removeHandler);
        window.addEventListener("keydown", this.removeHandler);
        window.addEventListener("mousewheel", this.removeHandler);
    }
Example #13
Source File: LineSegments2.js    From BlueMapWeb with MIT License 6 votes vote down vote up
LineSegments2 = function ( geometry, material ) {

	if ( geometry === undefined ) geometry = new LineSegmentsGeometry();
	if ( material === undefined ) material = new LineMaterial( { color: Math.random() * 0xffffff } );

	Mesh.call( this, geometry, material );

	this.type = 'LineSegments2';

}
Example #14
Source File: vr.js    From 3DTilesRendererJS with Apache License 2.0 6 votes vote down vote up
function buildController( data ) {

	let geometry, material;

	switch ( data.targetRayMode ) {

		case 'tracked-pointer':

			geometry = new BufferGeometry();
			geometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, - 1 ], 3 ) );
			geometry.setAttribute( 'color', new Float32BufferAttribute( [ 0.5, 0.5, 0.5, 0, 0, 0 ], 3 ) );

			material = new LineBasicMaterial( {
				vertexColors: true,
				blending: AdditiveBlending,
				depthWrite: false,
				transparent: true,
			} );

			return new Line( geometry, material );

		case 'gaze':

			geometry = new RingBufferGeometry( 0.02, 0.04, 32 ).translate( 0, 0, - 1 );
			material = new MeshBasicMaterial( { opacity: 0.5, transparent: true } );
			return new Mesh( geometry, material );

	}

}
Example #15
Source File: RectAreaLightHelper.js    From canvas with Apache License 2.0 6 votes vote down vote up
function RectAreaLightHelper( light, color ) {

	this.light = light;

	this.color = color; // optional hardwired color for the helper

	var positions = [ 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, - 1, 0, 1, 1, 0 ];

	var geometry = new BufferGeometry();
	geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
	geometry.computeBoundingSphere();

	var material = new LineBasicMaterial( { fog: false } );

	Line.call( this, geometry, material );

	this.type = 'RectAreaLightHelper';

	//

	var positions2 = [ 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, - 1, 0, 1, - 1, 0 ];

	var geometry2 = new BufferGeometry();
	geometry2.setAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) );
	geometry2.computeBoundingSphere();

	this.add( new Mesh( geometry2, new MeshBasicMaterial( { side: BackSide, fog: false } ) ) );

	this.update();

}
Example #16
Source File: saver.js    From HeroSaver-v2 with GNU General Public License v3.0 6 votes vote down vote up
function process(object3d, smooth, mirroredPose) {
    var material = new MeshBasicMaterial();
    var group = new Group();

    object3d.traverseVisible(function (object) {
        if (object.isMesh) {

            var exporter = new finalizeMesh();
            var geometry = exporter.parse(object);

            if (mirroredPose == true) {
              geometry = mirror(geometry)
            }

            if (smooth
                && object.name != 'baseRim'
                && object.name != 'base') {
                geometry = subdivide(geometry, smooth);
            }

            var mesh = new Mesh(geometry, material);

            group.add(mesh);
        }
    });
    return group;
}
Example #17
Source File: edge.js    From architect3d with MIT License 5 votes vote down vote up
// start, end have x and y attributes (i.e. corners)
	makeWall(start, end, transform, invTransform, material)
	{
		var v1 = this.toVec3(start);
		var v2 = this.toVec3(end);
		var v3 = v2.clone();
		var v4 = v1.clone();
		
		v3.y = this.edge.getEnd().elevation;
		v4.y = this.edge.getStart().elevation;
		
//		v3.y = this.wall.getClosestCorner(end).elevation;
//		v4.y = this.wall.getClosestCorner(start).elevation;
		
		var points = [v1.clone(), v2.clone(), v3.clone(), v4.clone()];

		points.forEach((p) => {p.applyMatrix4(transform);});

		var spoints = [new Vector2(points[0].x, points[0].y),new Vector2(points[1].x, points[1].y),new Vector2(points[2].x, points[2].y),new Vector2(points[3].x, points[3].y)];
		var shape = new Shape(spoints);

		// add holes for each wall item
		this.wall.items.forEach((item) => {
			var pos = item.position.clone();
			pos.applyMatrix4(transform);
			var halfSize = item.halfSize;
			var min = halfSize.clone().multiplyScalar(-1);
			var max = halfSize.clone();
			min.add(pos);
			max.add(pos);

			var holePoints = [new Vector2(min.x, min.y),new Vector2(max.x, min.y),new Vector2(max.x, max.y),new Vector2(min.x, max.y)];
			shape.holes.push(new Path(holePoints));
		});

		var geometry = new ShapeGeometry(shape);
		geometry.vertices.forEach((v) => {
			v.applyMatrix4(invTransform);
		});

		// make UVs
		var totalDistance = Utils.distance(new Vector2(v1.x, v1.z), new Vector2(v2.x, v2.z));
		var height = this.wall.height;
		geometry.faceVertexUvs[0] = [];

		geometry.faces.forEach((face) => {
			var vertA = geometry.vertices[face.a];
			var vertB = geometry.vertices[face.b];
			var vertC = geometry.vertices[face.c];
			geometry.faceVertexUvs[0].push([vertexToUv(vertA),vertexToUv(vertB),vertexToUv(vertC)]);
		});

		geometry.faceVertexUvs[1] = geometry.faceVertexUvs[0];
		geometry.computeFaceNormals();
		geometry.computeVertexNormals();

		function vertexToUv(vertex)
		{
			var x = Utils.distance(new Vector2(v1.x, v1.z), new Vector2(vertex.x, vertex.z)) / totalDistance;
			var y = vertex.y / height;
			return new Vector2(x, y);
		}

		var mesh = new Mesh(geometry, material);
		mesh.name = 'wall';
		return mesh;
	}
Example #18
Source File: ChunkManager.js    From webmc with MIT License 5 votes vote down vote up
addChunk (cellId, vert) {
    const geometry = new BufferGeometry()
    geometry.setAttribute('position', new BufferAttribute(new Float32Array(vert.positions), 3))
    geometry.setAttribute('normal', new BufferAttribute(new Float32Array(vert.normals), 3))
    geometry.setAttribute('uv', new BufferAttribute(new Float32Array(vert.uvs), 2))
    geometry.setAttribute('color', new BufferAttribute(new Float32Array(vert.colors), 3))
    geometry.matrixAutoUpdate = true

    const mesh = this.cellMesh.get(cellId)
    if (mesh === undefined) {
      const newMesh = new Mesh(geometry, this.game.world.material)
      newMesh.matrixAutoUpdate = true
      newMesh.frustumCulled = false
      newMesh.onAfterRender = () => {
        newMesh.frustumCulled = true
        newMesh.onAfterRender = function () {}
      }
      this.cellMesh.set(cellId, newMesh)
      this.game.scene.add(newMesh)
      if (this.smooth) {
        newMesh.position.y = -32
        const to = {
          y: 0
        }
        new TWEEN.Tween(newMesh.position)
          .to(to, 1000)
          .easing(TWEEN.Easing.Quadratic.Out)
          .onComplete(() => {
            newMesh.matrixAutoUpdate = true
            newMesh.geometry.matrixAutoUpdate = true
          })
          .start()
      }
      if (this.game.world.lastPlayerChunk !== null) {
        this.updateRenderOrder(JSON.parse(this.game.world.lastPlayerChunk))
      }
    } else {
      this.cellMesh.get(cellId).geometry = geometry
    }
  }
Example #19
Source File: LightProbeHelper.js    From canvas with Apache License 2.0 5 votes vote down vote up
LightProbeHelper.prototype = Object.create( Mesh.prototype );
Example #20
Source File: index.js    From map33.js with MIT License 5 votes vote down vote up
buildmesh() {
    this.buildMaterial().then((material) => {
      this.mesh.material = material
    })
    this.mesh = new Mesh(this.geometry, tileMaterial)
  }
Example #21
Source File: VoxelLoader.js    From three-voxel-loader with MIT License 5 votes vote down vote up
/**
   * Generates a polygon mesh with cubes based on voxel data.
   * One cube for each voxel.
   * @param {PointOctree} octree Octree with voxel data stored as points in space.
   * @returns {Mesh} 3D mesh based on voxel data
   */
  generateMesh(octree) {

    let mergedGeometry = new Geometry();
    const material = this.material;

    for (const leaf of octree.leaves()) {
      if (leaf.points !== null) {
        const pos = new Vector3();
        var i;
        let min = { x: leaf.points[0].x, y: leaf.points[0].y, z: leaf.points[0].z };
        let max = { x: leaf.points[0].x, y: leaf.points[0].y, z: leaf.points[0].z };

        for (i = 0; i < leaf.points.length; i++) {
          const point = leaf.points[i];
          pos.add(point);
          min.x = Math.min(min.x, point.x);
          min.y = Math.min(min.y, point.y);
          min.z = Math.min(min.z, point.z);
          max.x = Math.max(max.x, point.x);
          max.y = Math.max(max.y, point.y);
          max.z = Math.max(max.z, point.z);
        }

        let width = Math.round((this.voxelSize + (max.x - min.x)) * 100) / 100;;
        let height = Math.round((this.voxelSize + (max.y - min.y)) * 100) / 100;;
        let depth = Math.round((this.voxelSize + (max.z - min.z)) * 100) / 100;

        let voxelGeometry = new BoxGeometry(width, height, depth);
        pos.divideScalar(i);

        const rgb = leaf.data[0].color;
        if (rgb != null) {
          const color = new Color().setRGB(rgb.r / 255, rgb.g / 255, rgb.b / 255);

          for (var i = 0; i < voxelGeometry.faces.length; i++) {
            let face = voxelGeometry.faces[i];
            face.color.set(color);
          }
        }

        voxelGeometry.translate(pos.x, pos.y, pos.z);
        mergedGeometry.merge(voxelGeometry);
        voxelGeometry.translate(-pos.x, -pos.y, -pos.z);
      }
    }

    let bufGeometry = new BufferGeometry().fromGeometry(mergedGeometry);
    bufGeometry.computeFaceNormals();
    bufGeometry.computeVertexNormals();

    var voxels = new Mesh(bufGeometry, material);

    return voxels;
  }
Example #22
Source File: skybox.js    From architect3d with MIT License 5 votes vote down vote up
constructor(scene, renderer)
	{
		super();
		
		this.defaultEnvironment = 'rooms/textures/envs/Garden.png';
		this.useEnvironment = false;
		this.topColor = 0x92b2ce;//0xe9e9e9; //0xf9f9f9;//0x565e63
		this.bottomColor = 0xffffff;//0xD8ECF9
		this.verticalOffset = 400;
		this.exponent = 0.5;
		
		var uniforms = {topColor: {type: 'c',value: new Color(this.topColor)},bottomColor: {type: 'c',value: new Color(this.bottomColor)},offset: {type: 'f',value: this.verticalOffset}, exponent: {type:'f', value: this.exponent}};
		
		this.scene = scene;
		this.renderer = renderer;
		
		this.sphereRadius = 4000;
		this.widthSegments = 32;
		this.heightSegments = 15;
		this.sky = null;

		this.plainVertexShader = ['varying vec3 vWorldPosition;','void main() {','vec4 worldPosition = modelMatrix * vec4( position, 1.0 );','vWorldPosition = worldPosition.xyz;','gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0 );','}'].join('\n');
		this.plainFragmentShader = ['uniform vec3 bottomColor;','uniform vec3 topColor;','uniform float offset;','uniform float exponent;','varying vec3 vWorldPosition;','void main() {',' float h = normalize( vWorldPosition + offset ).y;',' gl_FragColor = vec4( mix( bottomColor, topColor, max( pow( max(h, 0.0 ), exponent ), 0.0 ) ), 1.0 );','}'].join('\n');
		
		this.vertexShader = ['varying vec2 vUV;','void main() {','  vUV=uv;','  vec4 pos = vec4(position, 1.0);', '   gl_Position = projectionMatrix * modelViewMatrix * pos;','}'].join('\n');
		this.fragmentShader = ['uniform sampler2D texture;', 'varying vec2 vUV;', 'void main() {  ', 'vec4 sample = texture2D(texture, vUV);', 'gl_FragColor = vec4(sample.xyz, sample.w);' ,'}'].join('\n');
		
		this.texture = new TextureLoader();
		this.plainSkyMat = new ShaderMaterial({vertexShader: this.plainVertexShader,fragmentShader: this.plainFragmentShader,uniforms: uniforms, side: DoubleSide});
		this.skyMat = undefined;
		
		this.skyGeo = new SphereGeometry(this.sphereRadius, this.widthSegments, this.heightSegments);
		this.sky = new Mesh(this.skyGeo, this.skyMat);
//		this.sky.position.x += this.sphereRadius*0.5;
		
		
		var groundT = new TextureLoader().load('rooms/textures/Ground_4K.jpg', function(){});		
		groundT.wrapS = groundT.wrapT = RepeatWrapping;
		groundT.repeat.set(10,10);
		
//		var uniforms2 = {topColor: {type: 'c',value: new Color(0xFFFFFF)},bottomColor: {type: 'c',value: new Color(0x999999)},offset: {type: 'f',value: this.verticalOffset}, exponent: {type:'f', value: this.exponent}};
		this.groundGeo = new PlaneGeometry(10000, 10000, 10);
		this.groundMat = new MeshBasicMaterial({color: 0xEAEAEA, side: DoubleSide, map:groundT });
		this.ground = new Mesh(this.groundGeo, this.groundMat);
		this.ground.rotateX(-Math.PI * 0.5);
		this.ground.position.y = -1;
		
		this.groundSceneReflector = new GroundSceneReflector(this.ground, this.renderer, this.scene,{textureOne:'rooms/textures/Ground_4K.jpg', textureTwo:'rooms/textures/GroundRough.jpg', wrapOne:{x:40, y:40}, wrapTwo:{x:50, y:50}, textureWidth: 512, textureHeight: 512, intensity: 0.1, blendIntensity: 0.05});
		
		this.scene.add(this.sky);
		this.scene.add(this.ground);
		
		var axesHelper = new AxesHelper( 100 );
		this.scene.add( axesHelper );
		
		this.init();
	}
Example #23
Source File: Water.js    From canvas with Apache License 2.0 5 votes vote down vote up
Water.prototype = Object.create( Mesh.prototype );
Example #24
Source File: ionExample.js    From 3DTilesRendererJS with Apache License 2.0 4 votes vote down vote up
function init() {

	scene = new Scene();

	// primary camera view
	renderer = new WebGLRenderer( { antialias: true } );
	renderer.setPixelRatio( window.devicePixelRatio );
	renderer.setSize( window.innerWidth, window.innerHeight );
	renderer.setClearColor( 0x151c1f );
	renderer.outputEncoding = sRGBEncoding;

	document.body.appendChild( renderer.domElement );
	renderer.domElement.tabIndex = 1;

	camera = new PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 4000 );
	camera.position.set( 400, 400, 400 );
	cameraHelper = new CameraHelper( camera );
	scene.add( cameraHelper );

	orthoCamera = new OrthographicCamera();
	orthoCameraHelper = new CameraHelper( orthoCamera );
	scene.add( orthoCameraHelper );

	// secondary camera view
	secondCamera = new PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 4000 );
	secondCamera.position.set( 400, 400, - 400 );
	secondCamera.lookAt( 0, 0, 0 );

	secondRenderer = new WebGLRenderer( { antialias: true } );
	secondRenderer.setPixelRatio( window.devicePixelRatio );
	secondRenderer.setSize( window.innerWidth, window.innerHeight );
	secondRenderer.setClearColor( 0x151c1f );
	secondRenderer.outputEncoding = sRGBEncoding;

	document.body.appendChild( secondRenderer.domElement );
	secondRenderer.domElement.style.position = 'absolute';
	secondRenderer.domElement.style.right = '0';
	secondRenderer.domElement.style.top = '0';
	secondRenderer.domElement.style.outline = '#0f1416 solid 2px';
	secondRenderer.domElement.tabIndex = 1;

	secondControls = new FlyOrbitControls( secondCamera, secondRenderer.domElement );
	secondControls.screenSpacePanning = false;
	secondControls.minDistance = 1;
	secondControls.maxDistance = 2000;

	secondCameraHelper = new CameraHelper( secondCamera );
	scene.add( secondCameraHelper );

	// Third person camera view
	thirdPersonCamera = new PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 4000 );
	thirdPersonCamera.position.set( 50, 40, 40 );
	thirdPersonCamera.lookAt( 0, 0, 0 );

	thirdPersonRenderer = new WebGLRenderer( { antialias: true } );
	thirdPersonRenderer.setPixelRatio( window.devicePixelRatio );
	thirdPersonRenderer.setSize( window.innerWidth, window.innerHeight );
	thirdPersonRenderer.setClearColor( 0x0f1416 );
	thirdPersonRenderer.outputEncoding = sRGBEncoding;

	document.body.appendChild( thirdPersonRenderer.domElement );
	thirdPersonRenderer.domElement.style.position = 'fixed';
	thirdPersonRenderer.domElement.style.left = '5px';
	thirdPersonRenderer.domElement.style.bottom = '5px';
	thirdPersonRenderer.domElement.tabIndex = 1;

	thirdPersonControls = new FlyOrbitControls( thirdPersonCamera, thirdPersonRenderer.domElement );
	thirdPersonControls.screenSpacePanning = false;
	thirdPersonControls.minDistance = 1;
	thirdPersonControls.maxDistance = 2000;

	// controls
	controls = new FlyOrbitControls( camera, renderer.domElement );
	controls.screenSpacePanning = false;
	controls.minDistance = 1;
	controls.maxDistance = 2000;

	// lights
	const dirLight = new DirectionalLight( 0xffffff );
	dirLight.position.set( 1, 2, 3 );
	scene.add( dirLight );

	const ambLight = new AmbientLight( 0xffffff, 0.2 );
	scene.add( ambLight );

	offsetParent = new Group();
	scene.add( offsetParent );

	// Raycasting init
	raycaster = new Raycaster();
	mouse = new Vector2();

	rayIntersect = new Group();

	const rayIntersectMat = new MeshBasicMaterial( { color: 0xe91e63 } );
	const rayMesh = new Mesh( new CylinderBufferGeometry( 0.25, 0.25, 6 ), rayIntersectMat );
	rayMesh.rotation.x = Math.PI / 2;
	rayMesh.position.z += 3;
	rayIntersect.add( rayMesh );

	const rayRing = new Mesh( new TorusBufferGeometry( 1.5, 0.2, 16, 100 ), rayIntersectMat );
	rayIntersect.add( rayRing );
	scene.add( rayIntersect );
	rayIntersect.visible = false;

	reinstantiateTiles();

	onWindowResize();
	window.addEventListener( 'resize', onWindowResize, false );
	renderer.domElement.addEventListener( 'mousemove', onMouseMove, false );
	renderer.domElement.addEventListener( 'mousedown', onMouseDown, false );
	renderer.domElement.addEventListener( 'mouseup', onMouseUp, false );
	renderer.domElement.addEventListener( 'mouseleave', onMouseLeave, false );

	secondRenderer.domElement.addEventListener( 'mousemove', onMouseMove, false );
	secondRenderer.domElement.addEventListener( 'mousedown', onMouseDown, false );
	secondRenderer.domElement.addEventListener( 'mouseup', onMouseUp, false );
	secondRenderer.domElement.addEventListener( 'mouseleave', onMouseLeave, false );


	// GUI
	const gui = new GUI();
	gui.width = 300;

	const ionOptions = gui.addFolder( 'Ion' );
	ionOptions.add( params, 'ionAssetId' );
	ionOptions.add( params, 'ionAccessToken' );
	ionOptions.add( params, 'reload' );
	ionOptions.open();

	const tileOptions = gui.addFolder( 'Tiles Options' );
	tileOptions.add( params, 'loadSiblings' );
	tileOptions.add( params, 'stopAtEmptyTiles' );
	tileOptions.add( params, 'displayActiveTiles' );
	tileOptions.add( params, 'errorTarget' ).min( 0 ).max( 50 );
	tileOptions.add( params, 'errorThreshold' ).min( 0 ).max( 1000 );
	tileOptions.add( params, 'maxDepth' ).min( 1 ).max( 100 );
	tileOptions.add( params, 'up', [ '+Y', '+Z', '-Z' ] );

	const debug = gui.addFolder( 'Debug Options' );
	debug.add( params, 'displayBoxBounds' );
	debug.add( params, 'colorMode', {

		NONE,
		SCREEN_ERROR,
		GEOMETRIC_ERROR,
		DISTANCE,
		DEPTH,
		RELATIVE_DEPTH,
		IS_LEAF,
		RANDOM_COLOR,

	} );

	const exampleOptions = gui.addFolder( 'Example Options' );
	exampleOptions.add( params, 'resolutionScale' ).min( 0.01 ).max( 2.0 ).step( 0.01 ).onChange( onWindowResize );
	exampleOptions.add( params, 'orthographic' );
	exampleOptions.add( params, 'showThirdPerson' );
	exampleOptions.add( params, 'showSecondView' ).onChange( onWindowResize );
	exampleOptions.add( params, 'enableUpdate' ).onChange( v => {

		tiles.parseQueue.autoUpdate = v;
		tiles.downloadQueue.autoUpdate = v;

		if ( v ) {

			tiles.parseQueue.scheduleJobRun();
			tiles.downloadQueue.scheduleJobRun();

		}

	} );
	exampleOptions.add( params, 'raycast', { NONE, ALL_HITS, FIRST_HIT_ONLY } );
	exampleOptions.add( params, 'enableCacheDisplay' );
	exampleOptions.add( params, 'enableRendererStats' );

	gui.open();

	statsContainer = document.createElement( 'div' );
	document.getElementById( 'info' ).appendChild( statsContainer );

	// Stats
	stats = new Stats();
	stats.showPanel( 0 );
	document.body.appendChild( stats.dom );

}
Example #25
Source File: item.js    From architect3d with MIT License 4 votes vote down vote up
/**
	 * Constructs an item.
	 *
	 * @param model
	 *            TODO
	 * @param metadata
	 *            TODO
	 * @param geometry
	 *            TODO
	 * @param material
	 *            TODO
	 * @param position
	 *            TODO
	 * @param rotation
	 *            TODO
	 * @param scale
	 *            TODO
	 */
	constructor(model, metadata, geometry, material, position, rotation, scale, isgltf=false)
	{
		super();

		this.model = model;
		this.metadata = metadata;

		/** */
		this.errorGlow = new Mesh();
		/** */
		this.hover = false;
		/** */
		this.selected = false;
		/** */
		this.highlighted = false;
		/** */
		this.error = false;
		/** */
		this.emissiveColor = 0x444444;
		/** Does this object affect other floor items */
		this.obstructFloorMoves = true;
		/** */
		this.position_set = false;
		/** Show rotate option in context menu */
		this.allowRotate = true;
		/** */
		this.fixed = false;
		/** dragging */
		this.dragOffset = new Vector3();
		/** */
		this.halfSize = new Vector3(0,0,0);
		this.bhelper = null;

		this.scene = this.model.scene;
		this._freePosition = true;

		if(!isgltf)
		{
				this.geometry = geometry;
				this.material = material;
				// center in its boundingbox
				this.geometry.computeBoundingBox();
				this.geometry.applyMatrix(new Matrix4().makeTranslation(- 0.5 * (this.geometry.boundingBox.max.x + this.geometry.boundingBox.min.x),- 0.5 * (this.geometry.boundingBox.max.y + this.geometry.boundingBox.min.y),- 0.5 * (this.geometry.boundingBox.max.z + this.geometry.boundingBox.min.z)));
				this.geometry.computeBoundingBox();
		}
		else
		{
				var objectBox = new Box3();
				objectBox.setFromObject(geometry);
				var hsize = objectBox.max.clone().sub(objectBox.min).multiplyScalar(0.5);
				this.geometry = new BoxGeometry(hsize.x*0.5, hsize.y*0.5, hsize.z*0.5);
				this.material =  new MeshStandardMaterial({color: 0x000000, wireframe: true, visible:false});
				this.geometry.computeBoundingBox();
				this.add(geometry);
		}

		if(!this.material.color)
		{
			this.material.color = new Color('#FFFFFF');
		}
		this.wirematerial = new MeshBasicMaterial({color: 0x000000, wireframe: true});

		this.errorColor = 0xff0000;

		this.resizable = metadata.resizable;

		this.castShadow = true;
		this.receiveShadow = false;

		this.originalmaterial = material;
		this.texture = this.material.texture;

		this.position_set = false;
		if (position)
		{
			this.position.copy(position);
			this.position_set = true;
		}

		this.halfSize = this.objectHalfSize();
		this.canvasWH = document.createElement('canvas');
		this.canvasWH.width = this.getWidth()+1.0;
		this.canvasWH.height = this.getHeight()+1.0;

		this.canvascontextWH = this.canvasWH.getContext('2d');
		this.canvasTextureWH = new CanvasTexture(this.canvasWH);
		this.canvasMaterialWH = new MeshBasicMaterial({map:this.canvasTextureWH, side: DoubleSide, transparent:true});
		this.canvasPlaneWH = new Mesh(new PlaneGeometry(this.getWidth(), this.getHeight(), 1, 1), this.canvasMaterialWH);
		this.canvasPlaneWH.scale.set(1, 1, 1);
		this.canvasPlaneWH.position.set(0, 0, this.getDepth()*0.5 + 0.3);

		this.canvasWD = document.createElement('canvas');
		this.canvasWD.width = this.getWidth()+1.0;
		this.canvasWD.height = this.getDepth()+1.0;

		this.canvascontextWD = this.canvasWD.getContext('2d');
		this.canvasTextureWD = new CanvasTexture(this.canvasWD);
		this.canvasMaterialWD = new MeshBasicMaterial({map:this.canvasTextureWD, side: DoubleSide, transparent:true});
		this.canvasPlaneWD = new Mesh(new PlaneGeometry(this.getWidth(), this.getDepth(), 1, 1), this.canvasMaterialWD);
		this.canvasPlaneWD.rotateX(-Math.PI * 0.5);
		this.canvasPlaneWD.scale.set(1, 1, 1);
		this.canvasPlaneWD.position.set(0, this.getHeight()*0.5 + 0.3, 0);
		this.canvasPlaneWH.visible = this.canvasPlaneWD.visible = false;

    this.add(this.canvasPlaneWH);
		this.add(this.canvasPlaneWD);
		this.resizeProportionally = true;

		if (rotation)
		{
			this.rotation.y = rotation;
		}

		if (scale != null)
		{
			this.setScale(scale.x, scale.y, scale.z);
		}

		if(this.metadata.materialColors)
		{
			if(this.metadata.materialColors.length)
			{
				if(this.material.length)
				{
					for (var i=0;i<this.metadata.materialColors.length;i++)
					{
						this.material[i].color = new Color(this.metadata.materialColors[i]);
					}
				}
				else
				{
					this.material.color = new Color(this.metadata.materialColors[0]);
				}
			}
		}
	}
Example #26
Source File: Pass.js    From three-viewer with MIT License 4 votes vote down vote up
/**
	 * Constructs a new pass.
	 *
	 * @param {String} [name] - The name of this pass. Does not have to be unique.
	 * @param {Scene} [scene] - The scene to render. The default scene contains a single mesh that fills the screen.
	 * @param {Camera} [camera] - A camera. Fullscreen effect passes don't require a camera.
	 */

	constructor(name = "Pass", scene = new Scene(), camera = dummyCamera) {

		/**
		 * The name of this pass.
		 *
		 * @type {String}
		 */

		this.name = name;

		/**
		 * The scene to render.
		 *
		 * @type {Scene}
		 * @protected
		 */

		this.scene = scene;

		/**
		 * The camera.
		 *
		 * @type {Camera}
		 * @protected
		 */

		this.camera = camera;

		/**
		 * A mesh that fills the screen.
		 *
		 * @type {Mesh}
		 * @private
		 */

		this.screen = null;

		/**
		 * Indicates whether this pass should render to texture.
		 *
		 * @type {Boolean}
		 * @private
		 */

		this.rtt = true;

		/**
		 * Only relevant for subclassing.
		 *
		 * Indicates whether the {@link EffectComposer} should swap the frame
		 * buffers after this pass has finished rendering.
		 *
		 * Set this to `false` if this pass doesn't render to the output buffer or
		 * the screen. Otherwise, the contents of the input buffer will be lost.
		 *
		 * @type {Boolean}
		 */

		this.needsSwap = true;

		/**
		 * Indicates whether the {@link EffectComposer} should prepare a depth
		 * texture for this pass.
		 *
		 * Set this to `true` if this pass relies on depth information from a
		 * preceding {@link RenderPass}.
		 *
		 * @type {Boolean}
		 */

		this.needsDepthTexture = false;

		/**
		 * Indicates whether this pass should be executed.
		 *
		 * @type {Boolean}
		 */

		this.enabled = true;

	}
Example #27
Source File: half_edge.js    From architect3d with MIT License 4 votes vote down vote up
/**
	 * Constructs a half edge.
	 * @param {Room} room The associated room. Instance of Room
	 * @param {Wall} wall The corresponding wall. Instance of Wall
	 * @param {boolean} front True if front side. Boolean value
	 */
	constructor(room, wall, front)
	{
		super();

		/**  The minimum point in space calculated from the bounds
		 * @property {Vector3} min  The minimum point in space calculated from the bounds
		 * @type {Vector3}
		 * @see https://threejs.org/docs/#api/en/math/Vector3
		**/
		this.min = null;
		
		/**
		 * The maximum point in space calculated from the bounds
		 * @property {Vector3} max	 The maximum point in space calculated from the bounds
		 * @type {Vector3}
		 * @see https://threejs.org/docs/#api/en/math/Vector3
		**/
		this.max = null;

		/**
		 * The center of this half edge
		 * @property {Vector3} center The center of this half edge
		 * @type {Vector3}
		 * @see https://threejs.org/docs/#api/en/math/Vector3
		**/
		this.center = null;

		/**
		 * Reference to a Room instance
		 * @property {Room} room Reference to a Room instance
		 * @type {Room}
		**/
		this.room = room;
		
		/** 
		 *  Reference to a Wall instance
		 * @property {Wall} room Reference to a Wall instance
		 * @type {Wall}
		**/
		this.wall = wall;
		
		/**
		 * Reference to the next halfedge instance connected to this
		 * @property {HalfEdge} next Reference to the next halfedge instance connected to this
		 * @type {HalfEdge}
		**/
		this.next = null;
		
		/**
		 * Reference to the previous halfedge instance connected to this
		 * @property {HalfEdge} prev Reference to the previous halfedge instance connected to this
		 * @type {HalfEdge}
		**/
		this.prev = null;
		
		/** 
		 * The offset to maintain for the front and back walls from the midline of a wall
		 * @property {Number} offset The offset to maintain for the front and back walls from the midline of a wall
		 * @type {Number}
		**/
		this.offset = 0.0;

		/**
		 *  The height of a wall
		 * @property {Number} height The height of a wall
		 * @type {Number}
		**/
		this.height = 0.0;
		
		/**
		 * The plane mesh that will be used for checking intersections of wall items
		 * @property {Mesh} plane The plane mesh that will be used for checking intersections of wall items
		 * @type {Mesh}
		 * @see https://threejs.org/docs/#api/en/objects/Mesh
		 */
		this.plane = null;
		
		/**
		 * The interior transformation matrix that contains the homogeneous transformation of the plane based on the two corner positions of the wall
		 * @property {Matrix4} interiorTransform The interior transformation matrix that contains the homogeneous transformation of the plane based on the two corner positions of the wall
		 * @type {Matrix4} 
		 * @see https://threejs.org/docs/#api/en/math/Matrix4
		 */
		this.interiorTransform = new Matrix4();
		
		/**
		 * The inverse of the interior transformation matrix that contains the homogeneous transformation of the plane based on the two corner positions of the wall
		 * @property {Matrix4} invInteriorTransform The inverse of the interior transformation matrix that contains the homogeneous transformation of the plane based on the two corner positions of the wall
		 * @type {Matrix4}
		 * @see https://threejs.org/docs/#api/en/math/Matrix4
		 */
		this.invInteriorTransform = new Matrix4();
		
		/**
		 * The exterior transformation matrix that contains the homogeneous transformation of the plane based on the two corner positions of the wall
		 * @property {Matrix4} exteriorTransform The exterior transformation matrix that contains the homogeneous transformation of the plane based on the two corner positions of the wall
		 * @type {Matrix4} 
		 * @see https://threejs.org/docs/#api/en/math/Matrix4
		 */
		this.exteriorTransform = new Matrix4();
		
		/**
		 * The inverse of the exterior transformation matrix that contains the homogeneous transformation of the plane based on the two corner positions of the wall
		 * @property {Matrix4} invExteriorTransform The inverse of the exterior transformation matrix that contains the homogeneous transformation of the plane based on the two corner positions of the wall
		 * @type {Matrix4}
		 * @see https://threejs.org/docs/#api/en/math/Matrix4
		 */
		this.invExteriorTransform = new Matrix4();
		
		/**
		 * This is an array of callbacks to be call when redraw happens
		 * @depreceated 
		 */
		this.redrawCallbacks = null;
		
		/**
		 * Is this is the front edge or the back edge
		 * @property {boolean} front Is this is the front edge or the back edge
		 * @type {boolean}
		 */
		this.front = front || false;
		
		this.offset = wall.thickness / 2.0;
		this.height = wall.height;

		if (this.front)
		{
			this.wall.frontEdge = this;
		}
		else
		{
			this.wall.backEdge = this;
		}

	}
Example #28
Source File: Handy.js    From handy.js with MIT License 4 votes vote down vote up
////////////////
   //            //
  //   Protos   //
 //            //
////////////////


//  Let’s define all the methods we want to
//  glob on to any object that we “make handy”.
//  We’ll store them in Handy’s ‘protos’ object.
//  https://en.wikipedia.org/wiki/Prototype-based_programming

Object.assign( Handy.protos, {


	//  Traverse down this THREE.Group to find
	//  a child with an ‘xrInputSource’ property,
	//  which should have a ‘handedness’ property.
	//  This will both assign that value to this Handy object
	// (if such a value is found)
	//  and return the current ‘handedness’ of this Handy object.

	//  NOTE: Is there a more efficient way to do this??

	checkHandedness: function(){

		const hand = this
		this.traverse( function( obj ){

			if( obj.xrInputSource !== undefined &&
				obj.xrInputSource.handedness !== undefined ){

				hand.handedness = obj.xrInputSource.handedness
				hand.name = 'hand '+ hand.handedness			
			}
		})
		return this.handedness
	},


	//  Find the distance (in CENTIMETERS!) between two joints
	//  by using joint name Strings.
	//  You can use the constant style ‘INDEX_PHALANX_INTERMEDIATE’
	//  or a more friendly lowercase-and-spaces style:
	// “index phalanx intermediate”. Both are valid styles here.
	//  This makes writing the pose detection logic super legible.
	//  Here’s some pinch detection logic:
	//
	//      return this.distanceBetweenJoints(
	//
	//          'index phalanx tip',
	// 		    'thumb phalanx tip'
	//	
	//       ) < 3
	//
	//  Easy, right?! Now you can write your own! :)

	distanceBetweenJoints: function( jointNameA, jointNameB ){

		if( this.joints.length === 0 ) return NaN

		const
		hand = this,
		[ jointA, jointB ] = [ jointNameA, jointNameB ]
		.map( function( name ){

			return hand.joints[ 

				// Handy[ name.toUpperCase().replace( /\s+/g, '_' )]
				name.toLowerCase().replace( /\s+/g, '-' )
			]
		})

		if( jointA.position && 
			jointB.position &&
			( !jointA.position.equals( jointB.position ))){

			return jointA.position.distanceTo( jointB.position ) * 100
		}
		else return NaN
	},


	//  Find the angle (in DEGREES!) from a finger’s base to its tip.
	//  Here’s how to check if your index finger is extended:
	//
	//      return this.digitAngle( 'index' ) < 20
	//  
	//  Not bad, eh?

	digitAngle: function( fingerName ){

		fingerName = fingerName.toLowerCase()

		const
		fingerTip = fingerName === 'thumb' ? 
			this.joints[ 'thumb-tip' ] :
			this.joints[ fingerName +'-finger-tip' ],
		fingerProximal = fingerName === 'thumb' ?
			this.joints[ 'thumb-phalanx-proximal' ] :
			this.joints[ fingerName +'-finger-phalanx-proximal' ]

		if( fingerTip && 
			fingerProximal && 
			fingerTip.quaternion &&
			fingerProximal.quaternion ){

			return MathUtils.radToDeg( 

				fingerProximal.quaternion.angleTo( fingerTip.quaternion )
			)
		}
		return NaN
	},


	//  Some useful helper functions that
	//  check the angle from digit base to digit tip
	//  to determine if that digit is extended
	//  or contracted.

	digitIsExtended: function( digitName ){

		return this.digitAngle( digitName ) < 45
	},
	digitIsContracted: function( digitName ){

		return this.digitAngle( digitName ) > 110
	},


	//  Useful for assessing 
	//  what values you may want to use
	//  in your detection functions.

	reportDigits: function(){

		const hand = this
		Handy.digitNames
		.forEach( function( digitName ){

			const 
			proximalName = digitName === 'thumb' ?
				'thumb-phalanx-proximal' :
				digitName +'-finger-phalanx-proximal',
			tipName = digitName === 'thumb' ?
				'thumb-tip' : 
				digitName + '-finger-tip',
			distance = hand.distanceBetweenJoints(

				proximalName,
				tipName
			),
			digitAngle = hand.digitAngle( digitName )

			console.log( 

				hand.handedness, 
				digitName +'.', 
				'angle:',
				Math.round( digitAngle )+'˚',
				'distance:',
				( Math.round( distance * 10 ) / 10 ) +'cm',
				hand.digitIsExtended( digitName ) ?
					'is extended' :
					'is contracted'
			)
		})
	},






	    ////////////////
	   //            //
	  //   Record   //
	 //            //
	////////////////


	//  Take a snapshot of this hand’s pose.

	readLivePoseData: function(){

		const 
		hand  = this,
		wrist = hand.joints[ 'wrist' ],
		jointPositions    = [],
		digitTipPositions = [],


		//  Take a position in global space,
		//  and make it relative to the wrist joint position
		//  also taking into account the wrist’s rotation.
		// (So we cannot simply subtract position vectors here!
		//  We must multiply the full transform matrices!)
		//  Also, let’s round these positions to the nearest
		//  millimeter to make things tidier to look at
		//  and save string space when stored as JSON data.

		preparePosition = function( joint ){

			const 
			jointMatrix = joint.matrix
			.clone()
			.premultiply( 

				// new THREE.Matrix4().copy( wrist.matrixWorld.invert() )
				wrist.matrixWorld.clone().invert()
			)

			
			//  Extract the X, Y, Z positions from the resulting matrix
			//  and return this as a flat Array
			//  with distances rounded to the nearest millimeter.
			
			return [ 

				Math.round( jointMatrix.elements[ 12 ] * 1000 ),
				Math.round( jointMatrix.elements[ 13 ] * 1000 ),
				Math.round( jointMatrix.elements[ 14 ] * 1000 )
			]
		},


		//  Store head (camera) position relative to the wrist. 
		//  In the future we’ll use this to identify hand gestures
		//  that relate to the position of the head / body.

		//  NOTE: Camera position is unreliable because of XR camera rig.
		//  Need to come back and investigate alternatives.

		headPosition = 
			wrist !== undefined && !wrist.position.equals( Handy.VECTOR3_ZERO )
			? preparePosition( hand.camera )
			: null,
		headRotation = 
			headPosition === null
			? null
			: hand.camera.quaternion.toArray()


		//  Store the positions of each joint relative to the wrist.
		//  Note that if a position is not “ready” 
		//  then that entry in the Array will be undefined.
		//  This is important during pose detection:
		//  Undefined elements will NOT accrue “distance”, ie.
		//  If the pinky finger positions don’t matter to a particular
		//  hand pose, you can just delete those entries!

		
		Object.values( hand.joints )
		.forEach( function( joint, i ){

			// console.log( i, 'joint', joint )

			if( joint !== undefined &&
				joint.position !== undefined &&
				joint.position.equals( Handy.VECTOR3_ZERO ) === false ){

				const preparedPosition = preparePosition( joint )
				jointPositions[ i ] = preparedPosition

				if( Handy.isDigitTipIndex( i )){

					digitTipPositions.push( preparedPosition )
				}
			}
		})
		
		// for( let i = 0; i < hand.joints.length; i ++ ){
			// const joint = hand.joints[ i ]
		// 	if( joint !== undefined &&
		// 		joint.position !== undefined &&
		// 		joint.position.equals( Handy.VECTOR3_ZERO ) === false ){

		// 		const preparedPosition = preparePosition( joint )
		// 		jointPositions[ i ] = preparedPosition

		// 		if( Handy.isDigitTipIndex( i )){

		// 			digitTipPositions.push( preparedPosition )
		// 		}
		// 	}
		// }


		//  Package it up and send it off.

		return { 

			headPosition,
			headRotation,
			jointPositions,
			digitTipPositions
		}
	},


	//  Grab a snapshot of the live hand pose,
	//  output its data to the JavaScript console
	// (so you can copy and paste it into your poses file),
	//  and also add it to the poses list
	//  so you can query for it immediately :)

	recordLivePose: function( name, showIt ){

		const 
		hand = this,
		handedness = hand.checkHandedness(),
		pose = Object.assign(

			{
				names: [ name ],
				handedness,				
				handyRevision: Handy.REVISION,
				time: Date.now()
			},
			hand.readLivePoseData()
		)
		
		console.log( '\n\nPOSE DEFINITION\n\n'+ JSON.stringify( pose ) +',\n\n\n' )
		Handy.poses[ handedness ].push( pose )
		if( showIt ) hand.showPose( pose, hand.joints[ 0 ].matrixWorld )
		return pose
	},


	//  Did your pose record correctly just now?
	//  This is a quick and dirty way to see 
	// (within XR!) if it’s roughly correct.

	showPose: function( pose, matrix ){

		const
		hand  = this,
		handRoot = new Object3D(),
		size = 0.02

		pose.jointPositions
		.forEach( function( position ){

			const box = new Mesh(
				new BoxBufferGeometry( size, size, size ),
				new MeshBasicMaterial()
			)
			box.position.fromArray( position ).multiplyScalar( 0.001 )
			if( matrix !== undefined ){
			
				box.updateMatrix()
				box.matrix.multiply( matrix )
			}
			else {

				box.position.y += 1
			}
			handRoot.add( box )
		})
		handRoot.position.copy( hand.position )
		hand.camera.parent.add( handRoot )
	},


	//  We can also show previously recorded poses.

	showPoseByName: function( poseName, matrix ){

		const
		hand  = this,
		pose = Handy.poses[ hand.handedness ]
		.find( function( pose ){ 

			return pose.names.includes( poseName )
		})

		if( pose ) hand.showPose( pose, matrix )
	},






	    ////////////////
	   //            //
	  //   Search   //
	 //            //
	////////////////


	//  Upon casually discussing Handy with a good friend of mine,
	//  Robert Gerard Pietrusko (http://warning-office.org),
	//  he suggessted I try recording hand poses and measuring the
	//  Euclidean distance between them.
	//  https://en.wikipedia.org/wiki/K-means_clustering
	//  This turned out to be very efficient! Sort of like Word2Vec,
	//  but for hands. https://en.wikipedia.org/wiki/Word2vec
	//
 	//  Question is, do we try Cosine Distance in the future?
	//  https://cmry.github.io/notes/euclidean-v-cosine

	livePoseData: [],
	searchLoopBeganAt: null,
	searchLoopsCounter: 0,
	searchLoopsCounterMax: 0,
	searchPoseIndex: 0,
	searchResultsBuffer:  [],
	searchResults: [],
	searchResultsHistory: [],//  For future use. (Will add gesture recognition.)
	searchMethod: 'jointPositions',
	lastSearchResult: { name: 'null' },

	search: function(){
		
		const 
		hand   = this,
		handedness = hand.checkHandedness(),
		poses = Handy.poses[ handedness ],
		method = hand.searchMethod


		//  Is our handedness undefined?
		//  Do we have zero poses to detect?
		//  If so, bail immediately!

		if( poses === undefined || poses.length === 0 ) return


		//  We’re going to do some serious “Array clutching” here.
		//  That means we may NOT finish looping through the Array
		//  before we “run out of time.” Why do this? Because if we’re
		//  running at 72fps or 90fps, etc. and we really only need
		//  to do a full poses search a few times per second,
		//  then we have render loops to spare and we ought to get
		//  out of the way as quickly as possible so that YOU can
		//  use that render loop time for yourself :)

		//  If you want more performance than this, then it’s time
		//  for Web Workers. But for now this seems to do the trick.
		//  https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API

		hand.searchLoopBeganAt = window.performance.now()
		for( let 
			
			i = hand.searchPoseIndex; 
			i < poses.length; 
			i ++ 
		){
		

			//  If we’re just beginning a new search
			//  we need to reset our results buffer
			//  and ask for new live hand pose data.

			if( i === 0 ){

				hand.searchLoopsCounter = 0
				hand.searchResultsBuffer = []
				hand.livePoseData = hand.readLivePoseData()


				//  If there’s no joint position data
				//  or if the wrist position of this hand is EXACTLY zero 
				// (in which case it’s likely ALL joint positions are zero)
				//  then this live data is useless. (So bail!)

				if( hand.livePoseData.jointPositions.length === 0 ||
					( 
						hand.livePoseData.jointPositions[ 0 ][ 0 ] === 0 &&
						hand.livePoseData.jointPositions[ 0 ][ 1 ] === 0 &&
						hand.livePoseData.jointPositions[ 0 ][ 2 ] === 0
					)){

					return
				}


				//  These flags assert that we are 
				//  NOT taking the square root of each distance.
				//  As this might change in the future
				//  I wanted a way for you to query / write logic
				//  around that.
				
				hand.searchResultsBuffer.distancesAreSquared = true
				hand.searchResultsBuffer.distancesAreRooted  = false
			}
	

			//  Go about our normal business.
			//  eg, evaluate the distance between this hand pose
			//  and the current-ish state of our real hand.

			const pose = poses[ i ]


			//  Currently we have two methods for detecting poses.
			// (Down from FOUR in a previous iteration! Sadly,
			//  the angles between wrist quaternion and digit tip
			//  weren’t sufficient once we added all of ASL.)
			//  We may eventually remove this digitTipPositions method
			//  as [all] jointPositions is obviously more accurate
			//  and seems speedy enough. 

			if( method === 'digitTipPositions' ){
				
				hand.searchResultsBuffer.push({

					pose,
					distance: pose.digitTipPositions
					.reduce( function( distance, digitTipPosition, i ){

						if( digitTipPosition.length !== undefined && 
							hand.livePoseData.digitTipPositions[ i ] !== undefined &&
							hand.livePoseData.digitTipPositions[ i ].length > 0 ){


							//  The “correct” way to do this is to take the square root
							//  of this sum. But find a square root is inherently slow.
							//  Thankfully we can do just as well by NOT taking the root.
							//  I leave it here (commented out) for your edification ;)

							distance += //Math.sqrt(

								Math.pow( digitTipPosition[ 0 ] - hand.livePoseData.digitTipPositions[ i ][ 0 ], 2 ) +
								Math.pow( digitTipPosition[ 1 ] - hand.livePoseData.digitTipPositions[ i ][ 1 ], 2 ) +
								Math.pow( digitTipPosition[ 2 ] - hand.livePoseData.digitTipPositions[ i ][ 2 ], 2 )
							//)
						}
						return distance

					}, 0 )
				})
			}
			else if( method === 'jointPositions' ){

				hand.searchResultsBuffer.push({

					pose,
					distance: pose.jointPositions
					.reduce( function( distance, jointPosition, i ){

						if( jointPosition.length !== undefined && 
							hand.livePoseData.jointPositions[ i ] !== undefined &&
							hand.livePoseData.jointPositions[ i ].length > 0 ){


							//  The “correct” way to do this is to take the square root
							//  of this sum. But find a square root is inherently slow.
							//  Thankfully we can do just as well by NOT taking the root.
							//  I leave it here (commented out) for your edification ;)

							distance += //Math.sqrt(

								Math.pow( jointPosition[ 0 ] - hand.livePoseData.jointPositions[ i ][ 0 ], 2 ) +
								Math.pow( jointPosition[ 1 ] - hand.livePoseData.jointPositions[ i ][ 1 ], 2 ) +
								Math.pow( jointPosition[ 2 ] - hand.livePoseData.jointPositions[ i ][ 2 ], 2 )
							//)
						}
						return distance

					}, 0 )
				})
			}


			//  Let’s keep track of how many loops it’s taking
			//  to finish searching through our whole poses library;
			//  accessible with something like:
			//  Handy.hands.getLeft().searchLoopsCounterMax

			hand.searchLoopsCounter ++
			hand.searchLoopsCounterMax = Math.max(

				hand.searchLoopsCounterMax,
				hand.searchLoopsCounter
			)


			//  Are we done? (If so, shut it down.)

			if( i === poses.length - 1 ){

				hand.searchResults = hand.searchResultsBuffer
				.sort( function( a, b ){

					return a.distance - b.distance
				})
				const searchResult = hand.searchResults[ 0 ]


				//   Does this search result differ from the previous one?

				if( hand.lastSearchResult.pose !== searchResult.pose ){

					if( hand.lastSearchResult && hand.lastSearchResult.pose ){


						//  Fire custom events.
						//  We need to fire events for each name
						//  that is associated with this pose.
						//  Why would there be multiple names??
						//  For example, “ASL_2” is the same as “Peace”.
						//  Someone unfamiliar with American Sign Language
						//  and only concerned with recognizing “peace”
						//  ought to have that convenience.
						// (And the other way ’round as well!)

						hand.lastSearchResult.pose.names
						.forEach( function( poseName ){

							hand.dispatchEvent({

								type: poseName +' pose ended', 
								hand,
								pose: hand.lastSearchResult.pose,
								

								//  Open question here:
								//  Should this “distance” property be from this pose’s
								//  previous top-result status (as it is currently)
								//  or should it be from its new not-top-result status?
	
								distance: hand.lastSearchResult.distance,
								message:  hand.handedness.toUpperCase() +
									' hand “'+ poseName +'” pose ended'+
									' at a Euclidean distance of '+ hand.lastSearchResult.distance +'mm.'
							})
						})

						
						//  Should you need it, 
						//  here’s an easy way to get a “from / to” alert.
						//  NOTE: Do we need to include distances in here too?

						hand.dispatchEvent({

							type: 'pose changed', 
							hand,
							resultWas: hand.lastSearchResult,
							resultIs:  searchResult,
							message:   hand.handedness.toUpperCase() +
								' hand pose changed from '+ 
								JSON.stringify( hand.lastSearchResult.pose.names ) +
								' to '+ 
								JSON.stringify( searchResult.pose.names ) +'.'
						})
					}
					

					searchResult.pose.names
					.forEach( function( poseName ){

						hand.dispatchEvent({

							type: poseName +' pose began', 
							hand,
							pose:     searchResult.pose,
							distance: searchResult.distance,
							message:  hand.handedness.toUpperCase() +
								' hand “'+ poseName +'” pose began'+
								' at a Euclidean distance of '+ searchResult.distance +'mm.'
						})
					})


					//  We’re ready to make it final.
					//  Replace the prior searh result 
					//  with the current search result.

					hand.lastSearchResult = searchResult
				}
				else {

					// console.log( 'Same hand pose as last time' )
				}
				

				//  Get things ready for next search.

				hand.searchIndex = 0
				hand.searchResultsBuffer = []


				//  Bail both from this local “for” loop 
				//  and from this entire function.

				return searchResult
			}

		
			//  If we’re not done with our search, 
			//  check if this search is taking too long per update() loop.

			else {


				//  If we’re taking too long
				//  let’s note what index we should start at next time
				//  and bail for now.

				if( window.performance.now() 
					- hand.searchLoopBeganAt 
					> Handy.searchLoopDurationLimit ){

					hand.findPoseIndex = i + 1
					break
				}
			}
		}
	},


	//  If the pose is the top search result
	// (or it’s in the results list above a given distance threshold)
	//  return the result itself so it includes 
	//  all of the pose data as well as distance.
	//  Otherwise return false.

	//  NOTE: This “threshold” argument is tricky
	//  because search() calculates distance in mm
	//  from the recorded model.
	//  But we might need NORMALIZED results instead.

	isPose: function( poseName, threshold ){

		const hand = this
		if( typeof threshold === 'number' ){
			
			const result = hand.searchResults
			.find( function( result ){ 

				return (

					result.distance <= threshold &&
					result.pose.names.includes( poseName )
				)
			})
			return result ? result : false
		}
		else if( hand.searchResults.length ){

			return hand.searchResults[ 0 ].pose.names.includes( poseName ) ?
				hand.searchResults[ 0 ] :
				false
		}
		return false
	},




	//  Some leftover debugging functions.

	comparePoses: function( poseAName, poseBName ){

		const 
		hand = this,
		posesList = Handy.poses[ hand.handedness ],
		poseA = posesList.find( function( pose ){ return pose.name === poseAName }),
		poseB = posesList.find( function( pose ){ return pose.name === poseBName })
		
		let
		poseDistanceAbs = 0,
		poseDistanceSqr = 0

		for( let i = 0; i < poseA.positions.length; i ++ ){

			const 
			positionA = poseA.positions[ i ],
			positionB = poseB.positions[ i ],
			jointDistanceAbs = 
				Math.abs( positionA[ 0 ] - positionB[ 0 ]) +
				Math.abs( positionA[ 1 ] - positionB[ 1 ]) +
				Math.abs( positionA[ 2 ] - positionB[ 2 ]),
			jointDistanceSqr = Math.sqrt(
				
				Math.pow( positionA[ 0 ] - positionB[ 0 ], 2 ) +
				Math.pow( positionA[ 1 ] - positionB[ 1 ], 2 ) +
				Math.pow( positionA[ 2 ] - positionB[ 2 ], 2 )
			)
			
			// console.log( 

			// 	'i', i, 
			// 	'\n', positionA, 
			// 	'\n', positionB, 
			// 	'\nSqr distance:', jointDistanceSqr,
			// 	'\nAbs distance:', jointDistanceAbs,
			// )

			poseDistanceAbs += jointDistanceAbs
			poseDistanceSqr += jointDistanceSqr
		}
		console.log( 

			'\nThe distance between', poseAName, 'and', poseBName, 'is', 
			'\nAbs:', poseDistanceAbs, 
			'\nSqr:', poseDistanceSqr, 
			'\n\n'
		)
		return poseDistanceSqr
	},
	compareAllTo: function( inputPose ){
		
		const
		hand = this,
		posesList = Handy.poses[ hand.handedness ]

		return posesList
		.reduce( function( list, pose ){ 

			return list.concat({ 

				name: pose.name, 
				distance: hands.left.comparePoses( 'Fist', pose.name )
			})

		}, [])
		.sort( function( a, b ){ 

			return a.distance - b.distance
		})
	},






	    ////////////////
	   //            //
	  //   Update   //
	 //            //
	////////////////


	//  Did you add a pose name to the Handy.poseNames Array?
	//  Did you also define a check function for it?
	//  If so, this function -- which you must remember to call 
	//  from within your update loop -- will check the status 
	//  of each pose, set the boolean flags accordingly,
	//  and fire off events on the frame when the state changes.

	update: function( callback ){

		const hand = this

		//  Do you believe in magic?

		hand.search()


		//  Are we supposed to do something?
		
		if( typeof callback === 'function' ) callback( hand )
	}
})
Example #29
Source File: LineSegments2.js    From BlueMapWeb with MIT License 4 votes vote down vote up
LineSegments2.prototype = Object.assign( Object.create( Mesh.prototype ), {

	constructor: LineSegments2,

	isLineSegments2: true,

	computeLineDistances: ( function () { // for backwards-compatability, but could be a method of LineSegmentsGeometry...

		var start = new Vector3();
		var end = new 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 InstancedInterleavedBuffer( lineDistances, 2, 1 ); // d0, d1

			geometry.setAttribute( 'instanceDistanceStart', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 0 ) ); // d0
			geometry.setAttribute( 'instanceDistanceEnd', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 1 ) ); // d1

			return this;

		};

	}() ),

	raycast: ( function () {

		var start = new Vector4();
		var end = new Vector4();

		var ssOrigin = new Vector4();
		var ssOrigin3 = new Vector3();
		var mvMatrix = new Matrix4();
		var line = new Line3();
		var closestPoint = new Vector3();

		return function raycast( raycaster, intersects ) {

			if ( raycaster.camera === null ) {

				console.error( 'LineSegments2: "Raycaster.camera" needs to be set in order to raycast against LineSegments2.' );

			}

			var threshold = ( raycaster.params.Line2 !== undefined ) ? raycaster.params.Line2.threshold || 0 : 0;

			var ray = raycaster.ray;
			var camera = raycaster.camera;
			var projectionMatrix = camera.projectionMatrix;

			var geometry = this.geometry;
			var material = this.material;
			var resolution = material.resolution;
			var lineWidth = material.linewidth + threshold;

			var instanceStart = geometry.attributes.instanceStart;
			var instanceEnd = geometry.attributes.instanceEnd;

			// pick a point 1 unit out along the ray to avoid the ray origin
			// sitting at the camera origin which will cause "w" to be 0 when
			// applying the projection matrix.
			ray.at( 1, ssOrigin );

			// ndc space [ - 1.0, 1.0 ]
			ssOrigin.w = 1;
			ssOrigin.applyMatrix4( camera.matrixWorldInverse );
			ssOrigin.applyMatrix4( projectionMatrix );
			ssOrigin.multiplyScalar( 1 / ssOrigin.w );

			// screen space
			ssOrigin.x *= resolution.x / 2;
			ssOrigin.y *= resolution.y / 2;
			ssOrigin.z = 0;

			ssOrigin3.copy( ssOrigin );

			var matrixWorld = this.matrixWorld;
			mvMatrix.multiplyMatrices( camera.matrixWorldInverse, matrixWorld );

			for ( var i = 0, l = instanceStart.count; i < l; i ++ ) {

				start.fromBufferAttribute( instanceStart, i );
				end.fromBufferAttribute( instanceEnd, i );

				start.w = 1;
				end.w = 1;

				// camera space
				start.applyMatrix4( mvMatrix );
				end.applyMatrix4( mvMatrix );

				// clip space
				start.applyMatrix4( projectionMatrix );
				end.applyMatrix4( projectionMatrix );

				// ndc space [ - 1.0, 1.0 ]
				start.multiplyScalar( 1 / start.w );
				end.multiplyScalar( 1 / end.w );

				// skip the segment if it's outside the camera near and far planes
				var isBehindCameraNear = start.z < - 1 && end.z < - 1;
				var isPastCameraFar = start.z > 1 && end.z > 1;
				if ( isBehindCameraNear || isPastCameraFar ) {

					continue;

				}

				// screen space
				start.x *= resolution.x / 2;
				start.y *= resolution.y / 2;

				end.x *= resolution.x / 2;
				end.y *= resolution.y / 2;

				// create 2d segment
				line.start.copy( start );
				line.start.z = 0;

				line.end.copy( end );
				line.end.z = 0;

				// get closest point on ray to segment
				var param = line.closestPointToPointParameter( ssOrigin3, true );
				line.at( param, closestPoint );

				// check if the intersection point is within clip space
				var zPos = MathUtils.lerp( start.z, end.z, param );
				var isInClipSpace = zPos >= - 1 && zPos <= 1;

				var isInside = ssOrigin3.distanceTo( closestPoint ) < lineWidth * 0.5;

				if ( isInClipSpace && isInside ) {

					line.start.fromBufferAttribute( instanceStart, i );
					line.end.fromBufferAttribute( instanceEnd, i );

					line.start.applyMatrix4( matrixWorld );
					line.end.applyMatrix4( matrixWorld );

					var pointOnLine = new Vector3();
					var point = new Vector3();

					ray.distanceSqToSegment( line.start, line.end, point, pointOnLine );

					intersects.push( {

						point: point,
						pointOnLine: pointOnLine,
						distance: ray.origin.distanceTo( point ),

						object: this,
						face: null,
						faceIndex: i,
						uv: null,
						uv2: null,

					} );

				}

			}

		};

	}() )

} );